PageRenderTime 55ms CodeModel.GetById 27ms RepoModel.GetById 1ms app.codeStats 0ms

/closure/goog/date/relative.js

https://github.com/Digaku/closure-library
JavaScript | 430 lines | 155 code | 68 blank | 207 comment | 51 complexity | 8c29e87d30fc351d4ceee2bb6b75f55d MD5 | raw file
  1. // Copyright 2009 The Closure Library Authors. All Rights Reserved.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS-IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. /**
  15. * @fileoverview Functions for formatting relative dates. Such as "3 days ago"
  16. * "3 hours ago", "14 minutes ago", "12 days ago", "Today", "Yesterday".
  17. *
  18. */
  19. goog.provide('goog.date.relative');
  20. goog.require('goog.i18n.DateTimeFormat');
  21. /**
  22. * Number of milliseconds in a minute.
  23. * @type {number}
  24. * @private
  25. */
  26. goog.date.relative.MINUTE_MS_ = 60000;
  27. /**
  28. * Number of milliseconds in a day.
  29. * @type {number}
  30. * @private
  31. */
  32. goog.date.relative.DAY_MS_ = 86400000;
  33. /**
  34. * Enumeration used to identify time units internally.
  35. * @enum {number}
  36. * @private
  37. */
  38. goog.date.relative.Unit_ = {
  39. MINUTES: 0,
  40. HOURS: 1,
  41. DAYS: 2
  42. };
  43. /**
  44. * Full date formatter.
  45. * @type {goog.i18n.DateTimeFormat}
  46. * @private
  47. */
  48. goog.date.relative.fullDateFormatter_;
  49. /**
  50. * Short time formatter.
  51. * @type {goog.i18n.DateTimeFormat}
  52. * @private
  53. */
  54. goog.date.relative.shortTimeFormatter_;
  55. /**
  56. * Month-date formatter.
  57. * @type {goog.i18n.DateTimeFormat}
  58. * @private
  59. */
  60. goog.date.relative.monthDateFormatter_;
  61. /**
  62. * Returns a date in month format, e.g. Mar 15.
  63. * @param {Date} date The date object.
  64. * @return {string} The formatted string.
  65. * @private
  66. */
  67. goog.date.relative.formatMonth_ = function(date) {
  68. if (!goog.date.relative.monthDateFormatter_) {
  69. goog.date.relative.monthDateFormatter_ =
  70. new goog.i18n.DateTimeFormat('MMM dd');
  71. }
  72. return goog.date.relative.monthDateFormatter_.format(date);
  73. };
  74. /**
  75. * Returns a date in short-time format, e.g. 2:50 PM.
  76. * @param {Date|goog.date.DateTime} date The date object.
  77. * @return {string} The formatted string.
  78. * @private
  79. */
  80. goog.date.relative.formatShortTime_ = function(date) {
  81. if (!goog.date.relative.shortTimeFormatter_) {
  82. goog.date.relative.shortTimeFormatter_ = new goog.i18n.DateTimeFormat(
  83. goog.i18n.DateTimeFormat.Format.SHORT_TIME);
  84. }
  85. return goog.date.relative.shortTimeFormatter_.format(date);
  86. };
  87. /**
  88. * Returns a date in full date format, e.g. Tuesday, March 24, 2009.
  89. * @param {Date|goog.date.DateTime} date The date object.
  90. * @return {string} The formatted string.
  91. * @private
  92. */
  93. goog.date.relative.formatFullDate_ = function(date) {
  94. if (!goog.date.relative.fullDateFormatter_) {
  95. goog.date.relative.fullDateFormatter_ = new goog.i18n.DateTimeFormat(
  96. goog.i18n.DateTimeFormat.Format.FULL_DATE);
  97. }
  98. return goog.date.relative.fullDateFormatter_.format(date);
  99. };
  100. /**
  101. * Accepts a timestamp in milliseconds and outputs a relative time in the form
  102. * of "1 hour ago", "1 day ago", "in 1 hour", "in 2 days" etc. If the date
  103. * delta is over 2 weeks, then the output string will be empty.
  104. * @param {number} dateMs Date in milliseconds.
  105. * @return {string} The formatted date.
  106. */
  107. goog.date.relative.format = function(dateMs) {
  108. var now = goog.now();
  109. var delta = Math.floor((now - dateMs) / goog.date.relative.MINUTE_MS_);
  110. var future = false;
  111. if (delta < 0) {
  112. future = true;
  113. delta *= -1;
  114. }
  115. if (delta < 60) { // Minutes.
  116. return goog.date.relative.getMessage_(
  117. delta, future, goog.date.relative.Unit_.MINUTES);
  118. } else {
  119. delta = Math.floor(delta / 60);
  120. if (delta < 24) { // Hours.
  121. return goog.date.relative.getMessage_(
  122. delta, future, goog.date.relative.Unit_.HOURS);
  123. } else {
  124. // We can be more than 24 hours apart but still only 1 day apart, so we
  125. // compare the closest time from today against the target time to find
  126. // the number of days in the delta.
  127. var midnight = new Date(goog.now());
  128. midnight.setHours(0);
  129. midnight.setMinutes(0);
  130. midnight.setSeconds(0);
  131. midnight.setMilliseconds(0);
  132. // Convert to days ago.
  133. delta = Math.ceil(
  134. (midnight.getTime() - dateMs) / goog.date.relative.DAY_MS_);
  135. if (future) {
  136. delta *= -1;
  137. }
  138. // Uses days for less than 2-weeks.
  139. if (delta < 14) {
  140. return goog.date.relative.getMessage_(
  141. delta, future, goog.date.relative.Unit_.DAYS);
  142. } else {
  143. // For messages older than 2 weeks do not show anything. The client
  144. // should decide the date format to show.
  145. return '';
  146. }
  147. }
  148. }
  149. };
  150. /**
  151. * Accepts a timestamp in milliseconds and outputs a relative time in the form
  152. * of "1 hour ago", "1 day ago". All future times will be returned as 0 minutes
  153. * ago.
  154. *
  155. * This is provided for compatibility with users of the previous incarnation of
  156. * the above {@see #format} method who relied on it protecting against
  157. * future dates.
  158. *
  159. * @param {number} dateMs Date in milliseconds.
  160. * @return {string} The formatted date.
  161. */
  162. goog.date.relative.formatPast = function(dateMs) {
  163. var now = goog.now();
  164. if (now < dateMs) {
  165. dateMs = now;
  166. }
  167. return goog.date.relative.format(dateMs);
  168. };
  169. /**
  170. * Accepts a timestamp in milliseconds and outputs a relative day. i.e. "Today",
  171. * "Yesterday" or "Sept 15".
  172. *
  173. * @param {number} dateMs Date in milliseconds.
  174. * @return {string} The formatted date.
  175. */
  176. goog.date.relative.formatDay = function(dateMs) {
  177. var message;
  178. var today = new Date(goog.now());
  179. today.setHours(0);
  180. today.setMinutes(0);
  181. today.setSeconds(0);
  182. today.setMilliseconds(0);
  183. var yesterday = new Date(today.getTime() - goog.date.relative.DAY_MS_);
  184. if (today.getTime() < dateMs) {
  185. /** @desc Today. */
  186. var MSG_TODAY = goog.getMsg('Today');
  187. message = MSG_TODAY;
  188. } else if (yesterday.getTime() < dateMs) {
  189. /** @desc Yesterday. */
  190. var MSG_YESTERDAY = goog.getMsg('Yesterday');
  191. message = MSG_YESTERDAY;
  192. } else {
  193. message = goog.date.relative.formatMonth_(new Date(dateMs));
  194. }
  195. return message;
  196. };
  197. /**
  198. * Formats a date, adding the relative date in parenthesis. If the date is less
  199. * than 24 hours then the time will be printed, otherwise the full-date will be
  200. * used. Examples:
  201. * 2:20 PM (1 minute ago)
  202. * Monday, February 27, 2009 (4 days ago)
  203. * Tuesday, March 20, 2005 // Too long ago for a relative date.
  204. *
  205. * @param {Date|goog.date.DateTime} date A date object.
  206. * @param {string=} opt_shortTimeMsg An optional short time message can be
  207. * provided if available, so that it's not recalculated in this function.
  208. * @param {string=} opt_fullDateMsg An optional date message can be
  209. * provided if available, so that it's not recalculated in this function.
  210. * @return {string} The date string in the above form.
  211. */
  212. goog.date.relative.getDateString = function(
  213. date, opt_shortTimeMsg, opt_fullDateMsg) {
  214. return goog.date.relative.getDateString_(
  215. date, goog.date.relative.format, opt_shortTimeMsg, opt_fullDateMsg);
  216. };
  217. /**
  218. * Formats a date, adding the relative date in parenthesis. Functions the same
  219. * as #getDateString but ensures that the date is always seen to be in the past.
  220. * If the date is in the future, it will be shown as 0 minutes ago.
  221. *
  222. * This is provided for compatibility with users of the previous incarnation of
  223. * the above {@see #getDateString} method who relied on it protecting against
  224. * future dates.
  225. *
  226. * @param {Date|goog.date.DateTime} date A date object.
  227. * @param {string=} opt_shortTimeMsg An optional short time message can be
  228. * provided if available, so that it's not recalculated in this function.
  229. * @param {string=} opt_fullDateMsg An optional date message can be
  230. * provided if available, so that it's not recalculated in this function.
  231. * @return {string} The date string in the above form.
  232. */
  233. goog.date.relative.getPastDateString = function(
  234. date, opt_shortTimeMsg, opt_fullDateMsg) {
  235. return goog.date.relative.getDateString_(
  236. date, goog.date.relative.formatPast, opt_shortTimeMsg, opt_fullDateMsg);
  237. };
  238. /**
  239. * Formats a date, adding the relative date in parenthesis. If the date is less
  240. * than 24 hours then the time will be printed, otherwise the full-date will be
  241. * used. Examples:
  242. * 2:20 PM (1 minute ago)
  243. * Monday, February 27, 2009 (4 days ago)
  244. * Tuesday, March 20, 2005 // Too long ago for a relative date.
  245. *
  246. * @param {Date|goog.date.DateTime} date A date object.
  247. * @param {function(number) : string} relativeFormatter Function to use when
  248. * formatting the relative date.
  249. * @param {string=} opt_shortTimeMsg An optional short time message can be
  250. * provided if available, so that it's not recalculated in this function.
  251. * @param {string=} opt_fullDateMsg An optional date message can be
  252. * provided if available, so that it's not recalculated in this function.
  253. * @return {string} The date string in the above form.
  254. * @private
  255. */
  256. goog.date.relative.getDateString_ = function(
  257. date, relativeFormatter, opt_shortTimeMsg, opt_fullDateMsg) {
  258. var dateMs = date.getTime();
  259. var relativeDate = relativeFormatter(dateMs);
  260. if (relativeDate) {
  261. relativeDate = ' (' + relativeDate + ')';
  262. }
  263. var delta = Math.floor((goog.now() - dateMs) / goog.date.relative.MINUTE_MS_);
  264. if (delta < 60 * 24) {
  265. // TODO(user): this call raises an exception if date is a goog.date.Date.
  266. return (opt_shortTimeMsg || goog.date.relative.formatShortTime_(date)) +
  267. relativeDate;
  268. } else {
  269. return (opt_fullDateMsg || goog.date.relative.formatFullDate_(date)) +
  270. relativeDate;
  271. }
  272. };
  273. /**
  274. * Gets a localized relative date string for a given delta and unit.
  275. * @param {number} delta Number of minutes/hours/days.
  276. * @param {boolean} future Whether the delta is in the future.
  277. * @param {goog.date.relative.Unit_} unit The units the delta is in.
  278. * @return {string} The message.
  279. * @private
  280. */
  281. goog.date.relative.getMessage_ = function(delta, future, unit) {
  282. if (!future && unit == goog.date.relative.Unit_.MINUTES) {
  283. /**
  284. * @desc Relative date indicating how many minutes ago something happened
  285. * (singular).
  286. */
  287. var MSG_MINUTES_AGO_SINGULAR =
  288. goog.getMsg('{$num} minute ago', {'num' : delta});
  289. /**
  290. * @desc Relative date indicating how many minutes ago something happened
  291. * (plural).
  292. */
  293. var MSG_MINUTES_AGO_PLURAL =
  294. goog.getMsg('{$num} minutes ago', {'num' : delta});
  295. return delta == 1 ? MSG_MINUTES_AGO_SINGULAR : MSG_MINUTES_AGO_PLURAL;
  296. } else if (future && unit == goog.date.relative.Unit_.MINUTES) {
  297. /**
  298. * @desc Relative date indicating in how many minutes something happens
  299. * (singular).
  300. */
  301. var MSG_IN_MINUTES_SINGULAR =
  302. goog.getMsg('in {$num} minute', {'num' : delta});
  303. /**
  304. * @desc Relative date indicating in how many minutes something happens
  305. * (plural).
  306. */
  307. var MSG_IN_MINUTES_PLURAL =
  308. goog.getMsg('in {$num} minutes', {'num' : delta});
  309. return delta == 1 ? MSG_IN_MINUTES_SINGULAR : MSG_IN_MINUTES_PLURAL;
  310. } else if (!future && unit == goog.date.relative.Unit_.HOURS) {
  311. /**
  312. * @desc Relative date indicating how many hours ago something happened
  313. * (singular).
  314. */
  315. var MSG_HOURS_AGO_SINGULAR =
  316. goog.getMsg('{$num} hour ago', {'num' : delta});
  317. /**
  318. * @desc Relative date indicating how many hours ago something happened
  319. * (plural).
  320. */
  321. var MSG_HOURS_AGO_PLURAL = goog.getMsg('{$num} hours ago', {'num' : delta});
  322. return delta == 1 ? MSG_HOURS_AGO_SINGULAR : MSG_HOURS_AGO_PLURAL;
  323. } else if (future && unit == goog.date.relative.Unit_.HOURS) {
  324. /**
  325. * @desc Relative date indicating in how many hours something happens
  326. * (singular).
  327. */
  328. var MSG_IN_HOURS_SINGULAR = goog.getMsg('in {$num} hour', {'num' : delta});
  329. /**
  330. * @desc Relative date indicating in how many hours something happens
  331. * (plural).
  332. */
  333. var MSG_IN_HOURS_PLURAL = goog.getMsg('in {$num} hours', {'num' : delta});
  334. return delta == 1 ? MSG_IN_HOURS_SINGULAR : MSG_IN_HOURS_PLURAL;
  335. } else if (!future && unit == goog.date.relative.Unit_.DAYS) {
  336. /**
  337. * @desc Relative date indicating how many days ago something happened
  338. * (singular).
  339. */
  340. var MSG_DAYS_AGO_SINGULAR = goog.getMsg('{$num} day ago', {'num' : delta});
  341. /**
  342. * @desc Relative date indicating how many days ago something happened
  343. * (plural).
  344. */
  345. var MSG_DAYS_AGO_PLURAL = goog.getMsg('{$num} days ago', {'num' : delta});
  346. return delta == 1 ? MSG_DAYS_AGO_SINGULAR : MSG_DAYS_AGO_PLURAL;
  347. } else if (future && unit == goog.date.relative.Unit_.DAYS) {
  348. /**
  349. * @desc Relative date indicating in how many days something happens
  350. * (singular).
  351. */
  352. var MSG_IN_DAYS_SINGULAR = goog.getMsg('in {$num} day', {'num' : delta});
  353. /**
  354. * @desc Relative date indicating in how many days something happens
  355. * (plural).
  356. */
  357. var MSG_IN_DAYS_PLURAL = goog.getMsg('in {$num} days', {'num' : delta});
  358. return delta == 1 ? MSG_IN_DAYS_SINGULAR : MSG_IN_DAYS_PLURAL;
  359. } else {
  360. return '';
  361. }
  362. };