date_time_util.dart 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374
  1. import 'package:flutter/foundation.dart';
  2. import 'package:flutter/material.dart';
  3. import 'package:intl/intl.dart';
  4. import 'package:photos/core/constants.dart';
  5. import 'package:photos/theme/ente_theme.dart';
  6. const Set<int> monthWith31Days = {1, 3, 5, 7, 8, 10, 12};
  7. const Set<int> monthWith30Days = {4, 6, 9, 11};
  8. Map<int, String> _months = {
  9. 1: "Jan",
  10. 2: "Feb",
  11. 3: "Mar",
  12. 4: "Apr",
  13. 5: "May",
  14. 6: "Jun",
  15. 7: "Jul",
  16. 8: "Aug",
  17. 9: "Sep",
  18. 10: "Oct",
  19. 11: "Nov",
  20. 12: "Dec",
  21. };
  22. Map<int, String> _fullMonths = {
  23. 1: "January",
  24. 2: "February",
  25. 3: "March",
  26. 4: "April",
  27. 5: "May",
  28. 6: "June",
  29. 7: "July",
  30. 8: "August",
  31. 9: "September",
  32. 10: "October",
  33. 11: "November",
  34. 12: "December",
  35. };
  36. Map<int, String> _days = {
  37. 1: "Mon",
  38. 2: "Tue",
  39. 3: "Wed",
  40. 4: "Thu",
  41. 5: "Fri",
  42. 6: "Sat",
  43. 7: "Sun",
  44. };
  45. final currentYear = DateTime.now().year;
  46. const searchStartYear = 1970;
  47. //Jun 2022
  48. String getMonthAndYear(DateTime dateTime) {
  49. return _months[dateTime.month]! + " " + dateTime.year.toString();
  50. }
  51. int daysBetween(DateTime from, DateTime to) {
  52. from = DateTime(from.year, from.month, from.day);
  53. to = DateTime(to.year, to.month, to.day);
  54. return (to.difference(from).inHours / 24).round();
  55. }
  56. bool areFromSameDay(int firstCreationTime, int secondCreationTime) {
  57. final firstDate = DateTime.fromMicrosecondsSinceEpoch(firstCreationTime);
  58. final secondDate = DateTime.fromMicrosecondsSinceEpoch(secondCreationTime);
  59. return firstDate.year == secondDate.year &&
  60. firstDate.month == secondDate.month &&
  61. firstDate.day == secondDate.day;
  62. }
  63. //Thu, 30 Jun
  64. String getDayAndMonth(DateTime dateTime) {
  65. return _days[dateTime.weekday]! +
  66. ", " +
  67. dateTime.day.toString() +
  68. " " +
  69. _months[dateTime.month]!;
  70. }
  71. //30 Jun, 2022
  72. String getDateAndMonthAndYear(DateTime dateTime) {
  73. return dateTime.day.toString() +
  74. " " +
  75. _months[dateTime.month]! +
  76. ", " +
  77. dateTime.year.toString();
  78. }
  79. // Create link default names:
  80. // Same day: "Dec 19, 2022"
  81. // Same month: "Dec 19 - 22, 2022"
  82. // Base case: "Dec 19, 2022 - Jan 7, 2023"
  83. String getNameForDateRange(int firstCreationTime, int secondCreationTime) {
  84. final startTime = DateTime.fromMicrosecondsSinceEpoch(firstCreationTime);
  85. final endTime = DateTime.fromMicrosecondsSinceEpoch(secondCreationTime);
  86. // different year
  87. if (startTime.year != endTime.year) {
  88. return "${_months[startTime.month]!} ${startTime.day}, ${startTime.year} - "
  89. "${_months[endTime.month]!} ${endTime.day}, ${endTime.year}";
  90. }
  91. // same year, diff month
  92. if (startTime.month != endTime.month) {
  93. return "${_months[startTime.month]!} ${startTime.day} - "
  94. "${_months[endTime.month]!} ${endTime.day}, ${endTime.year}";
  95. }
  96. // same month and year, diff day
  97. if (startTime.day != endTime.day) {
  98. return "${_months[startTime.month]!} ${startTime.day} - "
  99. "${_months[endTime.month]!} ${endTime.day}, ${endTime.year}";
  100. }
  101. // same day
  102. return "${_months[endTime.month]!} ${endTime.day}, ${endTime.year}";
  103. }
  104. String getDay(DateTime dateTime) {
  105. return _days[dateTime.weekday]!;
  106. }
  107. String getMonth(DateTime dateTime) {
  108. return _months[dateTime.month]!;
  109. }
  110. String getFullMonth(DateTime dateTime) {
  111. return _fullMonths[dateTime.month]!;
  112. }
  113. String getAbbreviationOfYear(DateTime dateTime) {
  114. return (dateTime.year % 100).toString();
  115. }
  116. //14:32
  117. String getTime(DateTime dateTime) {
  118. final hours = dateTime.hour > 9
  119. ? dateTime.hour.toString()
  120. : "0" + dateTime.hour.toString();
  121. final minutes = dateTime.minute > 9
  122. ? dateTime.minute.toString()
  123. : "0" + dateTime.minute.toString();
  124. return hours + ":" + minutes;
  125. }
  126. //11:22 AM
  127. String getTimeIn12hrFormat(DateTime dateTime) {
  128. return DateFormat.jm().format(dateTime);
  129. }
  130. //Thu, Jun 30, 2022 - 14:32
  131. String getFormattedTime(DateTime dateTime) {
  132. return getDay(dateTime) +
  133. ", " +
  134. getMonth(dateTime) +
  135. " " +
  136. dateTime.day.toString() +
  137. ", " +
  138. dateTime.year.toString() +
  139. " - " +
  140. getTime(dateTime);
  141. }
  142. //30 Jun'22
  143. String getFormattedDate(DateTime dateTime) {
  144. return dateTime.day.toString() +
  145. " " +
  146. getMonth(dateTime) +
  147. "'" +
  148. getAbbreviationOfYear(dateTime);
  149. }
  150. String getFullDate(DateTime dateTime) {
  151. return getDay(dateTime) +
  152. ", " +
  153. getMonth(dateTime) +
  154. " " +
  155. dateTime.day.toString() +
  156. " " +
  157. dateTime.year.toString();
  158. }
  159. String daysLeft(int futureTime) {
  160. final int daysLeft = ((futureTime - DateTime.now().microsecondsSinceEpoch) /
  161. Duration.microsecondsPerDay)
  162. .ceil();
  163. return '$daysLeft day' + (daysLeft <= 1 ? "" : "s");
  164. }
  165. String formatDuration(Duration position) {
  166. final ms = position.inMilliseconds;
  167. int seconds = ms ~/ 1000;
  168. final int hours = seconds ~/ 3600;
  169. seconds = seconds % 3600;
  170. final minutes = seconds ~/ 60;
  171. seconds = seconds % 60;
  172. final hoursString = hours >= 10
  173. ? '$hours'
  174. : hours == 0
  175. ? '00'
  176. : '0$hours';
  177. final minutesString = minutes >= 10
  178. ? '$minutes'
  179. : minutes == 0
  180. ? '00'
  181. : '0$minutes';
  182. final secondsString = seconds >= 10
  183. ? '$seconds'
  184. : seconds == 0
  185. ? '00'
  186. : '0$seconds';
  187. final formattedTime =
  188. '${hoursString == '00' ? '' : hoursString + ':'}$minutesString:$secondsString';
  189. return formattedTime;
  190. }
  191. bool isLeapYear(DateTime dateTime) {
  192. final year = dateTime.year;
  193. if (year % 4 == 0) {
  194. if (year % 100 == 0) {
  195. if (year % 400 == 0) {
  196. return true;
  197. } else {
  198. return false;
  199. }
  200. } else {
  201. return true;
  202. }
  203. } else {
  204. return false;
  205. }
  206. }
  207. Widget getDayWidget(
  208. BuildContext context,
  209. int timestamp,
  210. int photoGridSize,
  211. ) {
  212. final colorScheme = getEnteColorScheme(context);
  213. final textTheme = getEnteTextTheme(context);
  214. final textStyle =
  215. photoGridSize < photoGridSizeMax ? textTheme.body : textTheme.small;
  216. final double horizontalPadding =
  217. photoGridSize < photoGridSizeMax ? 12.0 : 8.0;
  218. final double verticalPadding = photoGridSize < photoGridSizeMax ? 12.0 : 14.0;
  219. return Padding(
  220. padding: EdgeInsets.symmetric(
  221. horizontal: horizontalPadding,
  222. vertical: verticalPadding,
  223. ),
  224. child: Container(
  225. alignment: Alignment.centerLeft,
  226. child: Text(
  227. getDayTitle(timestamp),
  228. style: (getDayTitle(timestamp) == "Today")
  229. ? textStyle
  230. : textStyle.copyWith(color: colorScheme.textMuted),
  231. ),
  232. ),
  233. );
  234. }
  235. String getDayTitle(int timestamp) {
  236. final date = DateTime.fromMicrosecondsSinceEpoch(timestamp);
  237. final now = DateTime.now();
  238. var title = getDayAndMonth(date);
  239. if (date.year == now.year && date.month == now.month) {
  240. if (date.day == now.day) {
  241. title = "Today";
  242. } else if (date.day == now.day - 1) {
  243. title = "Yesterday";
  244. }
  245. }
  246. if (date.year != DateTime.now().year) {
  247. title += " " + date.year.toString();
  248. }
  249. return title;
  250. }
  251. String secondsToHHMMSS(int value) {
  252. int h, m, s;
  253. h = value ~/ 3600;
  254. m = ((value - h * 3600)) ~/ 60;
  255. s = value - (h * 3600) - (m * 60);
  256. final String hourLeft =
  257. h.toString().length < 2 ? "0" + h.toString() : h.toString();
  258. final String minuteLeft =
  259. m.toString().length < 2 ? "0" + m.toString() : m.toString();
  260. final String secondsLeft =
  261. s.toString().length < 2 ? "0" + s.toString() : s.toString();
  262. final String result = "$hourLeft:$minuteLeft:$secondsLeft";
  263. return result;
  264. }
  265. bool isValidDate({
  266. required int day,
  267. required int month,
  268. required int year,
  269. }) {
  270. if (day < 0 || day > 31 || month < 0 || month > 12 || year < 0) {
  271. return false;
  272. }
  273. if (monthWith30Days.contains(month) && day > 30) {
  274. return false;
  275. }
  276. if (month == 2) {
  277. if (day > 29) {
  278. return false;
  279. }
  280. if (day == 29 && year % 4 != 0) {
  281. return false;
  282. }
  283. }
  284. return true;
  285. }
  286. final RegExp exp = RegExp('[\\.A-Za-z]*');
  287. DateTime? parseDateTimeFromFileNameV2(
  288. String fileName, {
  289. /* to avoid parsing incorrect date time from the filename, the max and min
  290. year limits the chances of parsing incorrect date times
  291. */
  292. int minYear = 1990,
  293. int? maxYear,
  294. }) {
  295. // add next year to avoid corner cases for 31st Dec
  296. maxYear ??= currentYear + 1;
  297. String val = fileName.replaceAll(exp, '');
  298. if (val.isNotEmpty && !isNumeric(val[0])) {
  299. val = val.substring(1, val.length);
  300. }
  301. if (val.isNotEmpty && !isNumeric(val[val.length - 1])) {
  302. val = val.substring(0, val.length - 1);
  303. }
  304. final int countOfHyphen = val.split("-").length - 1;
  305. final int countUnderScore = val.split("_").length - 1;
  306. String valForParser = val;
  307. if (countOfHyphen == 1) {
  308. valForParser = val.replaceAll("-", "T");
  309. } else if (countUnderScore == 1 || countUnderScore == 2) {
  310. valForParser = val.replaceFirst("_", "T");
  311. if (countUnderScore == 2) {
  312. valForParser = valForParser.split("_")[0];
  313. }
  314. } else if (countOfHyphen == 2) {
  315. valForParser = val.replaceAll(".", ":");
  316. } else if (countOfHyphen == 6) {
  317. final splits = val.split("-");
  318. valForParser =
  319. "${splits[0]}${splits[1]}${splits[2]}T${splits[3]}${splits[4]}${splits[5]}";
  320. }
  321. final result = DateTime.tryParse(valForParser);
  322. if (kDebugMode && result == null) {
  323. debugPrint("Failed to parse $fileName dateTime from $valForParser");
  324. }
  325. if (result != null && result.year >= minYear && result.year <= maxYear) {
  326. return result;
  327. }
  328. return null;
  329. }
  330. bool isNumeric(String? s) {
  331. if (s == null) {
  332. return false;
  333. }
  334. return double.tryParse(s) != null;
  335. }