formatters.rs 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. /// Format satoshis as a whole number with Bitcoin symbol (BIP177)
  2. pub fn format_sats_as_btc(sats: u64) -> String {
  3. let sats_str = sats.to_string();
  4. let formatted_sats = if sats_str.len() > 3 {
  5. let mut result = String::new();
  6. let chars: Vec<char> = sats_str.chars().collect();
  7. let len = chars.len();
  8. for (i, ch) in chars.iter().enumerate() {
  9. // Add comma before every group of 3 digits from right to left
  10. if i > 0 && (len - i) % 3 == 0 {
  11. result.push(',');
  12. }
  13. result.push(*ch);
  14. }
  15. result
  16. } else {
  17. sats_str
  18. };
  19. format!("₿{formatted_sats}")
  20. }
  21. /// Format millisatoshis as satoshis (whole number) with Bitcoin symbol (BIP177)
  22. pub fn format_msats_as_btc(msats: u64) -> String {
  23. let sats = msats / 1000;
  24. let sats_str = sats.to_string();
  25. let formatted_sats = if sats_str.len() > 3 {
  26. let mut result = String::new();
  27. let chars: Vec<char> = sats_str.chars().collect();
  28. let len = chars.len();
  29. for (i, ch) in chars.iter().enumerate() {
  30. // Add comma before every group of 3 digits from right to left
  31. if i > 0 && (len - i) % 3 == 0 {
  32. result.push(',');
  33. }
  34. result.push(*ch);
  35. }
  36. result
  37. } else {
  38. sats_str
  39. };
  40. format!("₿{formatted_sats}")
  41. }
  42. /// Format a Unix timestamp as a human-readable date and time
  43. pub fn format_timestamp(timestamp: u64) -> String {
  44. use std::time::{SystemTime, UNIX_EPOCH};
  45. let now = SystemTime::now()
  46. .duration_since(UNIX_EPOCH)
  47. .unwrap_or_default()
  48. .as_secs();
  49. let diff = now.saturating_sub(timestamp);
  50. match diff {
  51. 0..=60 => "Just now".to_string(),
  52. 61..=3600 => format!("{} min ago", diff / 60),
  53. _ => {
  54. // For timestamps older than 1 hour, show UTC time
  55. // Convert to a simple UTC format
  56. let total_seconds = timestamp;
  57. let seconds = total_seconds % 60;
  58. let total_minutes = total_seconds / 60;
  59. let minutes = total_minutes % 60;
  60. let total_hours = total_minutes / 60;
  61. let hours = total_hours % 24;
  62. let days = total_hours / 24;
  63. // Calculate year, month, day from days since epoch (1970-01-01)
  64. let mut year = 1970;
  65. let mut remaining_days = days;
  66. // Simple year calculation
  67. loop {
  68. let is_leap_year = (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0);
  69. let days_in_year = if is_leap_year { 366 } else { 365 };
  70. if remaining_days >= days_in_year {
  71. remaining_days -= days_in_year;
  72. year += 1;
  73. } else {
  74. break;
  75. }
  76. }
  77. // Calculate month and day
  78. let is_leap_year = (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0);
  79. let days_in_months = if is_leap_year {
  80. [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
  81. } else {
  82. [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
  83. };
  84. let mut month = 1;
  85. let mut day = remaining_days + 1;
  86. for &days_in_month in &days_in_months {
  87. if day > days_in_month {
  88. day -= days_in_month;
  89. month += 1;
  90. } else {
  91. break;
  92. }
  93. }
  94. format!(
  95. "{:04}-{:02}-{:02} {:02}:{:02}:{:02} UTC",
  96. year, month, day, hours, minutes, seconds
  97. )
  98. }
  99. }
  100. }
  101. #[cfg(test)]
  102. mod tests {
  103. use super::*;
  104. #[test]
  105. fn test_format_timestamp() {
  106. use std::time::{SystemTime, UNIX_EPOCH};
  107. let now = SystemTime::now()
  108. .duration_since(UNIX_EPOCH)
  109. .unwrap()
  110. .as_secs();
  111. // Test "Just now" (30 seconds ago)
  112. let recent = now - 30;
  113. assert_eq!(format_timestamp(recent), "Just now");
  114. // Test minutes ago (30 minutes ago)
  115. let minutes_ago = now - (30 * 60);
  116. assert_eq!(format_timestamp(minutes_ago), "30 min ago");
  117. // Test UTC format for older timestamps (2 hours ago)
  118. let hours_ago = now - (2 * 60 * 60);
  119. let result = format_timestamp(hours_ago);
  120. assert!(result.ends_with(" UTC"));
  121. assert!(result.contains("-"));
  122. assert!(result.contains(":"));
  123. // Test known timestamp: January 1, 2020 00:00:00 UTC
  124. let timestamp_2020 = 1577836800; // 2020-01-01 00:00:00 UTC
  125. let result = format_timestamp(timestamp_2020);
  126. assert_eq!(result, "2020-01-01 00:00:00 UTC");
  127. }
  128. }