date-fns-extra.ts 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. /* eslint-disable max-len */
  2. /* eslint-disable eqeqeq */
  3. import {
  4. toDate,
  5. format as dateFnsFormat,
  6. utcToZonedTime as dateFnsUtcToZonedTime,
  7. zonedTimeToUtc as dateFnsZonedTimeToUtc,
  8. OptionsWithTZ
  9. } from 'date-fns-tz';
  10. import { parse as dateFnsParse } from 'date-fns';
  11. /**
  12. * Need to be IANA logo without daylight saving time
  13. */
  14. export const IANAOffsetMap = [
  15. [-11, ['Pacific/Midway']],
  16. [-10, ['Pacific/Honolulu']],
  17. [-9.5, ['Pacific/Marquesas']],
  18. [-9, ['Pacific/Gambier']],
  19. [-8, ['Pacific/Pitcairn']],
  20. [-7, ['America/Phoenix']],
  21. [-6, ['America/Tegucigalpa']],
  22. [-5, ['America/Bogota']],
  23. [-4, ['America/Puerto_Rico']],
  24. [-3.5, ['America/St_Johns']], // No alternative daylight saving time zone
  25. [-3, ['America/Montevideo']],
  26. [-2, ['Atlantic/South_Georgia']],
  27. [-1, ['Atlantic/Cape_Verde']],
  28. [0, ['Africa/Accra']],
  29. [1, ['Africa/Bangui']],
  30. [2, ['Africa/Cairo']],
  31. [3, ['Asia/Bahrain', 'Indian/Antananarivo']],
  32. [3.5, ['Asia/Tehran']], // No alternative daylight saving time zone
  33. [4, ['Asia/Dubai', 'Asia/Muscat']],
  34. [4.5, ['Asia/Kabul']],
  35. [5, ['Asia/Samarkand', 'Asia/Karachi']],
  36. [5.5, ['Asia/Kolkata']],
  37. [5.75, ['Asia/Kathmandu']],
  38. [6, ['Asia/Dhaka']],
  39. [6.5, ['Asia/Rangoon', 'Asia/Rangoon']],
  40. [7, ['Asia/Jakarta', 'Asia/Phnom_Penh', 'Asia/Bangkok']],
  41. [8, ['Asia/Shanghai', 'Asia/Singapore']],
  42. [8.75, ['Australia/Eucla']],
  43. [9, ['Asia/Tokyo', 'Asia/Seoul', 'Asia/Pyongyang']],
  44. [9.5, ['Australia/Darwin']],
  45. [10, ['Pacific/Guam']],
  46. [10.5, ['Australia/Adelaide']], // No alternative daylight saving time zone
  47. [11, ['Pacific/Guadalcanal']],
  48. [12, ['Pacific/Funafuti']],
  49. [13, ['Pacific/Enderbury']],
  50. [13.75, ['Pacific/Chatham']], // No alternative daylight saving time zone
  51. [14, ['Pacific/Kiritimati']],
  52. ];
  53. const GMTStringReg = /([\-\+]{1})(\d{2})\:(\d{2})/;
  54. /**
  55. *
  56. * @param {string|number} tz
  57. * @returns {number|undefined}
  58. */
  59. export const toIANA = (tz: string | number) => {
  60. let matches = null;
  61. if (typeof tz === 'string') {
  62. matches = tz.match(GMTStringReg);
  63. if (!matches) {
  64. return tz;
  65. }
  66. const symbol = parseInt(matches[1] + 1, 10); // => -1 or 1
  67. const hourOffset = parseInt(matches[2], 10);
  68. const minuteOffset = parseInt(matches[3], 10);
  69. tz = symbol * (hourOffset + minuteOffset / 60);
  70. }
  71. if (typeof tz === 'number') {
  72. const found = IANAOffsetMap.find(item => item[0] === tz);
  73. return found && found[1][0];
  74. }
  75. };
  76. /**
  77. *
  78. * @param {string | number | Date} date
  79. * @param {string} formatToken
  80. * @param {object} [options]
  81. * @param {string} [options.timeZone]
  82. * @returns {Date}
  83. */
  84. /* istanbul ignore next */
  85. const parse = (date: string | number | Date, formatToken: string, options?: any) => {
  86. if (typeof date === 'string') {
  87. date = dateFnsParse(date, formatToken, new Date(), options);
  88. }
  89. if (options && options.timeZone != null && options.timeZone !== '') {
  90. const timeZone = toIANA(options.timeZone);
  91. options = { ...options, timeZone };
  92. }
  93. return toDate(date, options);
  94. };
  95. /* istanbul ignore next */
  96. const format = (date: number | Date, formatToken: string, options?: any) => {
  97. if (options && options.timeZone != null && options.timeZone !== '') {
  98. const timeZone = toIANA(options.timeZone);
  99. options = { ...options, timeZone };
  100. date = dateFnsUtcToZonedTime(date, timeZone, options);
  101. }
  102. return dateFnsFormat(date, formatToken, options);
  103. };
  104. /**
  105. * Returns a Date which will format as the local time of any time zone from a specific UTC time
  106. *
  107. * @example
  108. * ```javascript
  109. * import { utcToZonedTime } from 'date-fns-tz'
  110. * const { isoDate, timeZone } = fetchInitialValues() // 2014-06-25T10:00:00.000Z, America/New_York
  111. * const date = utcToZonedTime(isoDate, timeZone) // In June 10am UTC is 6am in New York (-04:00)
  112. * renderDatePicker(date) // 2014-06-25 06:00:00 (in the system time zone)
  113. * renderTimeZoneSelect(timeZone) // America/New_York
  114. * ```
  115. *
  116. * @see https://github.com/marnusw/date-fns-tz#utctozonedtime
  117. */
  118. const utcToZonedTime = (date: string | number | Date, timeZone: string | number, options?: OptionsWithTZ) => dateFnsUtcToZonedTime(date, toIANA(timeZone), options);
  119. /**
  120. * Given a date and any time zone, returns a Date with the equivalent UTC time
  121. *
  122. * @example
  123. * ```
  124. * import { zonedTimeToUtc } from 'date-fns-tz'
  125. * const date = getDatePickerValue() // e.g. 2014-06-25 10:00:00 (picked in any time zone)
  126. * const timeZone = getTimeZoneValue() // e.g. America/Los_Angeles
  127. * const utcDate = zonedTimeToUtc(date, timeZone) // In June 10am in Los Angeles is 5pm UTC
  128. * postToServer(utcDate.toISOString(), timeZone) // post 2014-06-25T17:00:00.000Z, America/Los_Angeles
  129. * ```
  130. *
  131. * @see https://github.com/marnusw/date-fns-tz#zonedtimetoutc
  132. */
  133. const zonedTimeToUtc = (date: string | number | Date, timeZone: string | number, options?: OptionsWithTZ) => dateFnsZonedTimeToUtc(date, toIANA(timeZone), options);
  134. /**
  135. * return current system hour offset based on utc:
  136. *
  137. * ```
  138. * 8 => "GMT+08:00"
  139. * -9.5 => "GMT-09:30"
  140. * -8 => "GMT-08:00"
  141. * ```
  142. */
  143. const getCurrentTimeZone = () => new Date().getTimezoneOffset() / 60;
  144. export { format, parse, utcToZonedTime, zonedTimeToUtc, getCurrentTimeZone };