diff --git a/nvflare/apis/impl/study_manager.py b/nvflare/apis/impl/study_manager.py index 1aff7de550e..b2a886b4b62 100644 --- a/nvflare/apis/impl/study_manager.py +++ b/nvflare/apis/impl/study_manager.py @@ -14,6 +14,7 @@ import json import logging +import time from datetime import date, datetime from typing import List, Optional, Tuple @@ -61,7 +62,7 @@ def add_study(self, study: Study, fl_ctx: FLContext) -> Tuple[Optional[Study], s - The name of the study must be unique; - participating_clients and participating_admins must be defined; - - Start and end date must make sense. + - Start and end time must make sense. Args: study: the caller-provided study info @@ -71,6 +72,8 @@ def add_study(self, study: Study, fl_ctx: FLContext) -> Tuple[Optional[Study], s updated study info (e.g. created_at is set) and an emtpy string if successful None and an error message if the provided study is not valid """ + if not isinstance(study, Study): + return None, f"Expect Study object, received {study.__class__.__name__}" if study.name in self._existing_studies: return None, "Unable to add duplicated study name." if not study.participating_clients: @@ -79,21 +82,21 @@ def add_study(self, study: Study, fl_ctx: FLContext) -> Tuple[Optional[Study], s return None, "Study has no contact info." if not study.participating_admins: return None, "Study has no participating admins." - if not study.start_date: - return None, "Study has no start date." - if not study.end_date: - return None, "Study has no end date." - if study.end_date < study.start_date: + if not study.start_time: + return None, "Study has no start time." + if not study.end_time: + return None, "Study has no end time." + if study.end_time < study.start_time: return ( None, - f"Expect end_date later than start_date. Got start_date={study.start_date} and end_data={study.end_date}", + f"Expect end_time later than start_time. Got start_time={study.start_time} and end_time={study.end_time}", ) - study.created_at = datetime.utcnow() + study.created_at = time.time() serialized_study = self._study_to_bytes(study) try: store = self._get_store(fl_ctx) except BaseException as e: - return None, e.message + return None, str(e) try: self._existing_studies = json.loads(store.get_data(StudyManager.STORAGE_KEY).decode("utf-8")) except BaseException: @@ -102,7 +105,7 @@ def add_study(self, study: Study, fl_ctx: FLContext) -> Tuple[Optional[Study], s store.create_object( uri=study.name, data=serialized_study, - meta={"start_date": study.start_date, "end_date": study.end_date}, + meta={"start_time": study.start_time, "end_time": study.end_time}, overwrite_existing=True, ) store.create_object( @@ -121,9 +124,6 @@ def add_study(self, study: Study, fl_ctx: FLContext) -> Tuple[Optional[Study], s def _study_from_bytes(bytes_study): try: deserialized_study = json.loads(bytes_study.decode("utf-8")) - deserialized_study["start_date"] = date.fromisoformat(deserialized_study.pop("start_date")) - deserialized_study["end_date"] = date.fromisoformat(deserialized_study.pop("end_date")) - deserialized_study["created_at"] = datetime.fromisoformat(deserialized_study.pop("created_at")) return Study(**deserialized_study) except BaseException: return None @@ -164,7 +164,7 @@ def list_active_studies(self, fl_ctx: FLContext) -> List[str]: Returns: A list of study names """ - today = date.today() + current_time = time.time() active_studies = list() try: store = self._get_store(fl_ctx) @@ -173,9 +173,9 @@ def list_active_studies(self, fl_ctx: FLContext) -> List[str]: for st in self.list_studies(fl_ctx): try: meta = store.get_meta(st) - if meta["start_date"] > today: + if meta["start_time"] > current_time: continue - if meta["end_date"] <= today: + if meta["end_time"] <= current_time: continue active_studies.append(st) except BaseException as e: diff --git a/nvflare/apis/study_manager_spec.py b/nvflare/apis/study_manager_spec.py index 2aa623a5e4e..a123024b0e3 100644 --- a/nvflare/apis/study_manager_spec.py +++ b/nvflare/apis/study_manager_spec.py @@ -13,7 +13,6 @@ # limitations under the License. from abc import ABC, abstractmethod -from datetime import date, datetime from typing import List, Optional, Tuple from .fl_context import FLContext @@ -30,18 +29,18 @@ def __init__( contact: str, participating_clients: List[str], participating_admins: List[str], - start_date: date, - end_date: date, + start_time: float, + end_time: float, reviewers=None, - created_at: datetime = None, + created_at: float = None, ): self.name = name self.description = description self.contact = contact self.participating_clients = participating_clients self.participating_admins = participating_admins - self.start_date = start_date - self.end_date = end_date + self.start_time = start_time + self.end_time = end_time self.reviewers = reviewers self.created_at = created_at diff --git a/nvflare/lighter/study.py b/nvflare/lighter/study.py index acd12b7aa1e..9f293264ac0 100644 --- a/nvflare/lighter/study.py +++ b/nvflare/lighter/study.py @@ -69,7 +69,7 @@ def get_datetime_input(prompt): answer = input(prompt) try: datetime_result = datetime.strptime(answer, "%m/%d/%Y %H:%M:%S") - result = int(time.mktime(datetime_result.timetuple())) + result = time.mktime(datetime_result.timetuple()) break except: print(f"Expect MM/DD/YYYY hh:mm:ss, but got {answer}")