All files / src/zones IANAZone.js

100% Statements 34/34
72.73% Branches 8/11
100% Functions 12/12
100% Lines 34/34
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104        32x                   2x 2x 2x 2x       283x 283x 283x 3113x 3113x   3113x 1698x     283x       47x 47x 42x   5x                   47x       47x 47x 47x       59x       34x       36x       4x       285x 285x                   285x     285x 285x 285x 285x       40x       128x      
import { Util } from '../impl/util';
import { Zone } from '../zone';
import { Settings } from '../settings';
 
const typeToPos = {
  year: 0,
  month: 1,
  day: 2,
  hour: 3,
  minute: 4,
  second: 5
};
 
function hackyOffset(dtf, date) {
  const formatted = dtf.format(date),
    parsed = /(\d+)\/(\d+)\/(\d+), (\d+):(\d+):(\d+)/.exec(formatted),
    [, fMonth, fDay, fYear, fHour, fMinute, fSecond] = parsed;
  return [fYear, fMonth, fDay, fHour, fMinute, fSecond];
}
 
function partsOffset(dtf, date) {
  const formatted = dtf.formatToParts(date),
    filled = [];
  for (let i = 0; i < formatted.length; i++) {
    const { type, value } = formatted[i],
      pos = typeToPos[type];
 
    if (!Util.isUndefined(pos)) {
      filled[pos] = parseInt(value, 10);
    }
  }
  return filled;
}
 
function isValid(zone) {
  try {
    new Intl.DateTimeFormat('en-US', { timeZone: zone }).format();
    return true;
  } catch (e) {
    return false;
  }
}
 
/**
 * @private
 */
 
export class IANAZone extends Zone {
  static isValidSpecier(s) {
    return s && s.match(/[a-z_]+\/[a-z_]+/i);
  }
 
  constructor(name) {
    super();
    this.zoneName = name;
    this.valid = isValid(name);
  }
 
  get type() {
    return 'iana';
  }
 
  get name() {
    return this.zoneName;
  }
 
  get universal() {
    return false;
  }
 
  offsetName(ts, { format = 'long', locale = Settings.defaultLocale } = {}) {
    return Util.parseZoneInfo(ts, format, locale, this.zoneName);
  }
 
  offset(ts) {
    const date = new Date(ts),
      dtf = new Intl.DateTimeFormat('en-US', {
        hour12: false,
        timeZone: this.zoneName,
        year: 'numeric',
        month: '2-digit',
        day: '2-digit',
        hour: '2-digit',
        minute: '2-digit',
        second: '2-digit'
      }),
      [fYear, fMonth, fDay, fHour, fMinute, fSecond] = dtf.formatToParts
        ? partsOffset(dtf, date)
        : hackyOffset(dtf, date),
      asUTC = Date.UTC(fYear, fMonth - 1, fDay, fHour, fMinute, fSecond);
    let asTS = date.valueOf();
    asTS -= asTS % 1000;
    return (asUTC - asTS) / (60 * 1000);
  }
 
  equals(otherZone) {
    return otherZone.type === 'iana' && otherZone.zoneName === this.zoneName;
  }
 
  get isValid() {
    return this.valid;
  }
}