Repository: getmoto/moto

Issue:
Make Redshift creation time to be UTC
Currently Redshift snapshot is initialized with `datetime.now()` instead of `datetime.utcnow()`. It should be UTC time for compatibility.

For reference see [models.py](https://github.com/spulec/moto/blob/master/moto/redshift/models.py). In cluster creation it is:
```python
self.create_time = iso_8601_datetime_with_milliseconds(datetime.datetime.utcnow())
```
And in snapshot creation it is:
```python
self.create_time = iso_8601_datetime_with_milliseconds(datetime.datetime.now())
```


Discussion:
Thanks for raising this @matanabudy - marking it as a bug to fix this
Hi, long time but it looks the bug hasn't been actually solved - there are still places (including the original one in the issue - `class Snapshot` - https://github.com/getmoto/moto/blob/b7624e10b1ec1e351c30b7f8dce76d4f33efcc69/moto/redshift/models.py#L537
Also happening in `RDS` in some places such as:
https://github.com/getmoto/moto/blob/b7624e10b1ec1e351c30b7f8dce76d4f33efcc69/moto/rds/models.py#L553

Resolving patch:
diff --git a/moto/rds/models.py b/moto/rds/models.py
--- a/moto/rds/models.py
+++ b/moto/rds/models.py
@@ -416,7 +416,6 @@ def remove_tags(self, tag_keys: List[str]) -> None:
 
 
 class ClusterSnapshot(BaseModel):
-
     SUPPORTED_FILTERS = {
         "db-cluster-id": FilterDef(
             ["cluster.db_cluster_arn", "cluster.db_cluster_identifier"],
@@ -486,7 +485,6 @@ def remove_tags(self, tag_keys: List[str]) -> None:
 
 
 class Database(CloudFormationModel):
-
     SUPPORTED_FILTERS = {
         "db-cluster-id": FilterDef(["db_cluster_identifier"], "DB Cluster Identifiers"),
         "db-instance-id": FilterDef(
@@ -551,7 +549,7 @@ def __init__(self, **kwargs: Any):
         self.db_instance_identifier = kwargs.get("db_instance_identifier")
         self.db_name = kwargs.get("db_name")
         self.instance_create_time = iso_8601_datetime_with_milliseconds(
-            datetime.datetime.now()
+            datetime.datetime.utcnow()
         )
         self.publicly_accessible = kwargs.get("publicly_accessible")
         if self.publicly_accessible is None:
@@ -1039,7 +1037,6 @@ def delete(self, account_id: str, region_name: str) -> None:
 
 
 class DatabaseSnapshot(BaseModel):
-
     SUPPORTED_FILTERS = {
         "db-instance-id": FilterDef(
             ["database.db_instance_arn", "database.db_instance_identifier"],
@@ -1058,7 +1055,9 @@ def __init__(
         self.snapshot_id = snapshot_id
         self.tags = tags
         self.status = "available"
-        self.created_at = iso_8601_datetime_with_milliseconds(datetime.datetime.now())
+        self.created_at = iso_8601_datetime_with_milliseconds(
+            datetime.datetime.utcnow()
+        )
 
     @property
     def snapshot_arn(self) -> str:
@@ -1135,7 +1134,9 @@ def __init__(
         self.export_only = kwargs.get("export_only", [])
 
         self.status = "complete"
-        self.created_at = iso_8601_datetime_with_milliseconds(datetime.datetime.now())
+        self.created_at = iso_8601_datetime_with_milliseconds(
+            datetime.datetime.utcnow()
+        )
         self.source_type = (
             "SNAPSHOT" if type(snapshot) is DatabaseSnapshot else "CLUSTER"
         )
@@ -1183,7 +1184,9 @@ def __init__(self, kwargs: Dict[str, Any]):
         self.region_name = ""
         self.customer_aws_id = kwargs["account_id"]
         self.status = "active"
-        self.created_at = iso_8601_datetime_with_milliseconds(datetime.datetime.now())
+        self.created_at = iso_8601_datetime_with_milliseconds(
+            datetime.datetime.utcnow()
+        )
 
     @property
     def es_arn(self) -> str:
diff --git a/moto/redshift/models.py b/moto/redshift/models.py
--- a/moto/redshift/models.py
+++ b/moto/redshift/models.py
@@ -31,7 +31,6 @@
 
 
 class TaggableResourceMixin:
-
     resource_type = ""
 
     def __init__(
@@ -61,7 +60,6 @@ def delete_tags(self, tag_keys: List[str]) -> List[Dict[str, str]]:
 
 
 class Cluster(TaggableResourceMixin, CloudFormationModel):
-
     resource_type = "cluster"
 
     def __init__(
@@ -330,7 +328,6 @@ def to_json(self) -> Dict[str, Any]:
 
 
 class SnapshotCopyGrant(TaggableResourceMixin, BaseModel):
-
     resource_type = "snapshotcopygrant"
 
     def __init__(self, snapshot_copy_grant_name: str, kms_key_id: str):
@@ -345,7 +342,6 @@ def to_json(self) -> Dict[str, Any]:
 
 
 class SubnetGroup(TaggableResourceMixin, CloudFormationModel):
-
     resource_type = "subnetgroup"
 
     def __init__(
@@ -425,7 +421,6 @@ def to_json(self) -> Dict[str, Any]:
 
 
 class SecurityGroup(TaggableResourceMixin, BaseModel):
-
     resource_type = "securitygroup"
 
     def __init__(
@@ -456,7 +451,6 @@ def to_json(self) -> Dict[str, Any]:
 
 
 class ParameterGroup(TaggableResourceMixin, CloudFormationModel):
-
     resource_type = "parametergroup"
 
     def __init__(
@@ -516,7 +510,6 @@ def to_json(self) -> Dict[str, Any]:
 
 
 class Snapshot(TaggableResourceMixin, BaseModel):
-
     resource_type = "snapshot"
 
     def __init__(
@@ -534,7 +527,9 @@ def __init__(
         self.snapshot_identifier = snapshot_identifier
         self.snapshot_type = snapshot_type
         self.status = "available"
-        self.create_time = iso_8601_datetime_with_milliseconds(datetime.datetime.now())
+        self.create_time = iso_8601_datetime_with_milliseconds(
+            datetime.datetime.utcnow()
+        )
         self.iam_roles_arn = iam_roles_arn or []
 
     @property
@@ -1086,7 +1081,9 @@ def get_cluster_credentials(
             raise InvalidParameterValueError(
                 "Token duration must be between 900 and 3600 seconds"
             )
-        expiration = datetime.datetime.now() + datetime.timedelta(0, duration_seconds)
+        expiration = datetime.datetime.utcnow() + datetime.timedelta(
+            0, duration_seconds
+        )
         if cluster_identifier in self.clusters:
             user_prefix = "IAM:" if auto_create is False else "IAMA:"
             db_user = user_prefix + db_user


Test patch: