diff --git a/parakeet/src/entities/core/post.rs b/parakeet/src/entities/core/post.rs index d7c7a9ee..f81cc985 100644 --- a/parakeet/src/entities/core/post.rs +++ b/parakeet/src/entities/core/post.rs @@ -617,7 +617,7 @@ impl PostEntity { record: serde_json::json!({ "$type": "app.bsky.feed.post", "text": text, - "createdAt": created_at.to_rfc3339(), + "createdAt": created_at.to_rfc3339_opts(chrono::SecondsFormat::Millis, true), }), embed: self.build_embed(&data), stats: RecordStats { @@ -670,7 +670,7 @@ impl PostEntity { parakeet_db::tid_util::encode_tid(data.post.rkey) ), "allow": allow, - "createdAt": chrono::Utc::now().to_rfc3339() + "createdAt": chrono::Utc::now().to_rfc3339_opts(chrono::SecondsFormat::Millis, true) }); Some(ThreadgateView { diff --git a/parakeet/src/entities/core/starterpack.rs b/parakeet/src/entities/core/starterpack.rs index 72420a9a..08811265 100644 --- a/parakeet/src/entities/core/starterpack.rs +++ b/parakeet/src/entities/core/starterpack.rs @@ -319,7 +319,7 @@ impl StarterpackEntity { None }, "feeds": Vec::::new(), // TODO: Need to fix load_feed_uris to work with actor_id/rkey - "createdAt": indexed_at.to_rfc3339(), + "createdAt": indexed_at.to_rfc3339_opts(chrono::SecondsFormat::Millis, true), }); // Query counts if list exists diff --git a/parakeet/src/xrpc/app_bsky/feed/get_timeline.rs b/parakeet/src/xrpc/app_bsky/feed/get_timeline.rs index 3bcfb2cd..6926ecda 100644 --- a/parakeet/src/xrpc/app_bsky/feed/get_timeline.rs +++ b/parakeet/src/xrpc/app_bsky/feed/get_timeline.rs @@ -116,7 +116,7 @@ pub async fn get_timeline( let cursor = if has_next && timeline_items.len() > limit as usize { let last_rkey = timeline_items[limit as usize - 1].0; let timestamp = parakeet_db::tid_util::tid_to_datetime(last_rkey); - Some(timestamp.to_rfc3339()) + Some(timestamp.to_rfc3339_opts(chrono::SecondsFormat::Millis, true)) } else { None }; @@ -263,7 +263,7 @@ pub async fn get_author_feed( let cursor = if has_next && posts_to_return.len() == limit as usize { let last_rkey = posts_to_return[posts_to_return.len() - 1].1; let timestamp = parakeet_db::tid_util::tid_to_datetime(last_rkey); - Some(timestamp.to_rfc3339()) + Some(timestamp.to_rfc3339_opts(chrono::SecondsFormat::Millis, true)) } else { None }; diff --git a/parakeet/src/xrpc/app_bsky/feed/likes.rs b/parakeet/src/xrpc/app_bsky/feed/likes.rs index 193fccda..bcf83c0e 100644 --- a/parakeet/src/xrpc/app_bsky/feed/likes.rs +++ b/parakeet/src/xrpc/app_bsky/feed/likes.rs @@ -47,7 +47,7 @@ pub async fn get_actor_likes( .map(|(_, rkey)| { // Convert TID to timestamp for cursor let dt = parakeet_db::tid_util::tid_to_datetime(*rkey); - dt.to_rfc3339() + dt.to_rfc3339_opts(chrono::SecondsFormat::Millis, true) }); // Build post URIs from results diff --git a/parakeet/src/xrpc/app_bsky/feed/posts/queries.rs b/parakeet/src/xrpc/app_bsky/feed/posts/queries.rs index 42119e6e..eabf132b 100644 --- a/parakeet/src/xrpc/app_bsky/feed/posts/queries.rs +++ b/parakeet/src/xrpc/app_bsky/feed/posts/queries.rs @@ -74,7 +74,7 @@ pub async fn get_post( let value = serde_json::json!({ "$type": "app.bsky.feed.post", "text": post_view.record.get("text").unwrap_or(&serde_json::Value::String("".to_string())), - "createdAt": post_view.indexed_at.to_rfc3339(), + "createdAt": post_view.indexed_at.to_rfc3339_opts(chrono::SecondsFormat::Millis, true), }); Ok(Json(PostRes { diff --git a/parakeet/src/xrpc/app_bsky/graph/lists.rs b/parakeet/src/xrpc/app_bsky/graph/lists.rs index faa7d2b6..dbcbfd9c 100644 --- a/parakeet/src/xrpc/app_bsky/graph/lists.rs +++ b/parakeet/src/xrpc/app_bsky/graph/lists.rs @@ -128,7 +128,7 @@ pub async fn get_list( // Calculate next cursor let cursor = item_results .last() - .map(|item| item.3.to_rfc3339()); + .map(|item| item.3.to_rfc3339_opts(chrono::SecondsFormat::Millis, true)); // Get profiles for all subject actor IDs let subject_ids: Vec = item_results diff --git a/parakeet/src/xrpc/app_bsky/notification.rs b/parakeet/src/xrpc/app_bsky/notification.rs index f191ab5f..ba7e4a41 100644 --- a/parakeet/src/xrpc/app_bsky/notification.rs +++ b/parakeet/src/xrpc/app_bsky/notification.rs @@ -335,8 +335,8 @@ pub async fn list_notifications( .collect(), ), description: profile_view.description.clone(), - created_at: Some(profile_view.created_at.to_rfc3339()), - indexed_at: Some(profile_view.indexed_at.to_rfc3339()), + created_at: Some(profile_view.created_at.to_rfc3339_opts(chrono::SecondsFormat::Millis, true)), + indexed_at: Some(profile_view.indexed_at.to_rfc3339_opts(chrono::SecondsFormat::Millis, true)), } } else { // Fallback if profile not found @@ -386,7 +386,7 @@ pub async fn list_notifications( reason_subject, record, is_read, - indexed_at: notif.indexed_at.to_rfc3339(), + indexed_at: notif.indexed_at.to_rfc3339_opts(chrono::SecondsFormat::Millis, true), labels: Some(Vec::new()), }); } @@ -396,7 +396,7 @@ pub async fn list_notifications( let cursor = next_cursor_id.map(|id| id.to_string()); // Format seen_at for response - let seen_at_response = seen_at.map(|dt| dt.to_rfc3339()); + let seen_at_response = seen_at.map(|dt| dt.to_rfc3339_opts(chrono::SecondsFormat::Millis, true)); tracing::info!("→ listNotifications: {:.1}ms total ({} notifications)", start.elapsed().as_secs_f64() * 1000.0, notifications.len()); @@ -616,7 +616,7 @@ fn build_notification_record( "subject": { "uri": subject_uri, }, - "createdAt": created_at.to_rfc3339(), + "createdAt": created_at.to_rfc3339_opts(chrono::SecondsFormat::Millis, true), }); } } @@ -633,7 +633,7 @@ fn build_notification_record( "subject": { "uri": post_uri, }, - "createdAt": created_at.to_rfc3339(), + "createdAt": created_at.to_rfc3339_opts(chrono::SecondsFormat::Millis, true), }); } } @@ -645,7 +645,7 @@ fn build_notification_record( return serde_json::json!({ "$type": "app.bsky.graph.follow", "subject": subject_did, - "createdAt": created_at.to_rfc3339(), + "createdAt": created_at.to_rfc3339_opts(chrono::SecondsFormat::Millis, true), }); } } @@ -657,7 +657,7 @@ fn build_notification_record( let mut record = serde_json::json!({ "$type": "app.bsky.feed.post", "text": content, - "createdAt": created_at.to_rfc3339(), + "createdAt": created_at.to_rfc3339_opts(chrono::SecondsFormat::Millis, true), }); // Construct parent/root URIs using actor_did_map