Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Time is but an Illusion.. in JavaScript! (JSConf JP)

Jenn
December 01, 2019

Time is but an Illusion.. in JavaScript! (JSConf JP)

With so much to worry about timing wise: formatting, time zones, internationalization, recurrence rules, leap years, daylight savings time, and more, everyone needs HELP!

Let’s turn time into money by taking a look at the most popular time libraries and how we use them to solve JavaScript’s time problems. We’ll look at how JavaScript’s Date object started and what its prototype allows. We’ll wind our way through dates, times, and standards to find solutions to the weirdness.

Let’s kill time together talking about JavaScript time! Because we know, time heals all.

Jenn

December 01, 2019
Tweet

More Decks by Jenn

Other Decks in Technology

Transcript

  1. @mybluewristband
    TIME.. IS BUT AN
    ILLUSION
    IN JAVASCRIPT!
    @mybluewristband

    View full-size slide

  2. @mybluewristband
    ୭Ͱ͔͢?
    Who am i?
    @mybluewristband

    View full-size slide

  3. @mybluewristband
    Jennifer Wong Mode analytics Mozilla tech speaker whovian

    View full-size slide

  4. @mybluewristband
    DOCTOR WHO
    Time Lord
    Sonic Screwdriver
    T.A.R.D.I.S
    Daleks
    @mybluewristband

    View full-size slide

  5. @mybluewristband
    @mybluewristband

    View full-size slide

  6. @mybluewristband
    Ͳ͏ͯ͠?
    What happened?

    View full-size slide

  7. @mybluewristband
    RECURRING
    INVITES
    A past project
    @mybluewristband

    View full-size slide

  8. @mybluewristband
    RECURRING INVITES
    Generate an recurrence rule (rrule) on the frontend (???) in iCal format
    All existing rrule libraries were 1.5+ years out of date
    But now there is an updated one: https://github.com/jakubroztocil/rrule
    So I wrote my own rrule library…
    Ensure timezone attached to rrule
    Timezone of office location, not employee
    Employees are based all over the world
    May create invites for people in other offices

    View full-size slide

  9. @mybluewristband
    @mybluewristband

    View full-size slide

  10. @mybluewristband
    @mybluewristband

    View full-size slide

  11. @mybluewristband
    FREQ=WEEKLY;
    BYDAY=FR;
    UNTIL=20190629T120000Z;

    View full-size slide

  12. @mybluewristband
    RECURRING INVITES - A PROBLEM
    We were in PST or GMT-7/GMT-8 (daylight savings)
    All tests would pass locally
    At 4pm/5pm PST/PDT, all frontend CI tests would fail for a few hours

    View full-size slide

  13. @mybluewristband
    RECURRING INVITES - A PROBLEM
    Some tests written with assuming a specific time zone (PST/PDT)
    But the CI server was in a different timezone
    Tests didn’t expect that times minutes or hours apart might be in different days

    View full-size slide

  14. @mybluewristband
    RECURRING INVITES - A SOLUTION KINDA
    Local testing vs CI testing issues
    Resolution: set a particular time/time zone in a test
    But this only reliably tests that specific time/time zone
    Also, undo any time mocking or the next test(s) will use the same time/time zone
    (and probably fail)

    View full-size slide


  15. @mybluewristband
    Don't write your own recurrence rule
    library. Doubly so for JavaScript.
    Jennifer Wong

    View full-size slide


  16. @mybluewristband
    Check the timezone of your CI server.
    Doubly so if it's running JavaScript
    tests.
    Jennifer Wong

    View full-size slide

  17. @mybluewristband
    ࣌ؒͷෆࢥٞ͞
    Time is weird.
    @mybluewristband

    View full-size slide

  18. @mybluewristband
    @mybluewristband

    View full-size slide

  19. @mybluewristband
    ࣌ؒ
    Tale as old as time
    @mybluewristband

    View full-size slide

  20. @mybluewristband
    HISTORY OF TIME
    https://en.wikipedia.org/wiki/Time
    Artifacts from Paleolithic era suggest the moon was used to reckon time
    Lunar calendars
    Earliest lunar calendar was discovered in 8000 BC.
    Years of either 12 or 13 lunar months (354 or 384 days)
    Egyptians created first time measurement devices
    T-square
    Sundial
    Water clock

    View full-size slide

  21. @mybluewristband
    TYPES OF TIME ZONES OR STANDARDS
    Greenwich Mean Time (GMT)
    Created in 1847 at the Royal Observatory in Greenwich
    Universal Coordinated Time (UTC)
    International Meridian Conference (of 26 nations)
    $ Colombia was there!
    & The United States was there!
    Unix Time
    Number of seconds that have passed since the Unix Epoch
    00:00:00 UTC Thursday, 1 January 1970
    International Standards Organization (ISO)

    View full-size slide

  22. @mybluewristband
    G
    M
    T
    !!!
    @mybluewristband

    View full-size slide

  23. @mybluewristband
    JAVASCRIPT
    DATE
    OBJECT
    It's old

    View full-size slide

  24. @mybluewristband
    @mybluewristband

    View full-size slide

  25. @mybluewristband
    ECMA-262
    JavaScript!
    Version 1 - 1997
    Only six new Date object methods have
    been added since then
    Date.prototype.toDateString()
    Date.prototype.toISOString()
    Date.prototype.toJSON()
    Date.prototype.toLocaleDateString()
    Date.prototype.toLocaleTimeString()
    Date.prototype.toTimeString()

    View full-size slide

  26. @mybluewristband
    WHY THE 0 INDEX
    JavaScript’s Date object has a zero indexed
    month
    java.util.Date had 0-indexed month
    java.time package was released in
    2014 with a 1-indexed month
    Moment.js uses a zero indexed month

    View full-size slide

  27. @mybluewristband
    https://stackoverflow.com/questions/2552483/why-does-the-month-argument-range-from-0-to-11-in-
    javascripts-date-constructor/41992352#41992352

    View full-size slide

  28. @mybluewristband
    https://stackoverflow.com/questions/2552483/why-does-the-month-argument-range-from-0-to-11-in-
    javascripts-date-constructor/41992352#41992352

    View full-size slide


  29. @mybluewristband
    Because Java.
    Brendan Eich (creator of JavaScript)

    View full-size slide

  30. @mybluewristband
    @mybluewristband

    View full-size slide

  31. @mybluewristband
    TYPE COERCION
    One can coerce a date to a number of milliseconds from the Unix Epoch
    simply by using:

    +new Date()
    @mybluewristband

    View full-size slide

  32. @mybluewristband
    JAVASCRIPT
    VERSUS
    MOMENT.JS
    FIGHT!
    @mybluewristband

    View full-size slide

  33. @mybluewristband
    GETTERS
    Go get 'em

    View full-size slide

  34. // Date Object
    Date.prototype.constructor
    Date.prototype.getDate()
    Date.prototype.getDay()
    Date.prototype.getFullYear()
    Date.prototype.getHours()
    Date.prototype.getMilliseconds()
    Date.prototype.getMinutes()
    Date.prototype.getMonth()
    Date.prototype.getSeconds()
    Date.prototype.getTime()
    Date.prototype.getTimezoneOffset()
    // Moment.js
    moment()
    moment().date()
    moment().day()
    moment().year()
    moment().hour()
    moment().millesecond()
    moment().minute()
    moment().month()
    moment().second()
    moment().get()
    moment().zone() // deprecated
    @mybluewristband

    View full-size slide

  35. // Date Object
    Date.prototype.getUTCDate()
    Date.prototype.getUTCDay()
    Date.prototype.getUTCFullYear()
    Date.prototype.getUTCHours()
    Date.prototype.getUTCMilliseconds()
    Date.prototype.getUTCMinutes()
    Date.prototype.getUTCMonth()
    Date.prototype.getUTCSeconds()
    // Moment.js
    moment().utc().date()
    moment().utc().day()
    moment().utc().year()
    moment().utc().hour()
    moment().utc().milleseconds()
    moment().utc().minutes()
    moment().utc().month()
    moment().utc().seconds()
    @mybluewristband

    View full-size slide

  36. @mybluewristband
    SETTERS
    Get, set, match (?)
    @mybluewristband

    View full-size slide

  37. // Date Object
    Date.prototype.setDate()
    Date.prototype.setFullYear()
    Date.prototype.setHours()
    Date.prototype.setMilliseconds()
    Date.prototype.setMinutes()
    Date.prototype.setMonth()
    Date.prototype.setSeconds()
    Date.prototype.setTime()
    Date.prototype.setYear()
    // deprecated
    // Moment.js
    moment().date()
    moment().year()
    moment().hour()
    moment().millesecond()
    moment().minute()
    moment().month()
    moment().second()
    moment().set()
    moment().year()
    @mybluewristband

    View full-size slide

  38. // Date Object
    Date.prototype.setUTCDate()
    Date.prototype.setUTCFullYear()
    Date.prototype.setUTCHours()
    Date.prototype.setUTCMilliseconds()
    Date.prototype.setUTCMinutes()
    Date.prototype.setUTCMonth()
    Date.prototype.setUTCSeconds()
    // Moment.js
    moment().utc().date()
    moment().utc().year()
    moment().utc().hour()
    moment().utc().milleseconds()
    moment().utc().minutes()
    moment().utc().month()
    moment().utc().seconds()
    @mybluewristband

    View full-size slide

  39. @mybluewristband
    OTHER METHODS
    I've got gadgets and gizmos a-plenty
    @mybluewristband

    View full-size slide

  40. @mybluewristband

    View full-size slide

  41. // Date Object
    Date.prototype.toDateString()
    Date.prototype.toISOString()
    Date.prototype.toJSON()
    Date.prototype.valueOf()
    // Returns milliseconds since
    // the Unix epoch which is
    // 1 January 1970 00:00:00 UTC
    // Moment.js
    moment().format('ddd MMM DD YYYY’)
    moment().utc().format('YYYY-MM-DDTHH:mm:ss.SSS') + 'Z'
    moment().utc().format('YYYY-MM-DDTHH:mm:ss.SSS') + 'Z'
    parseInt( moment().format('x'), 10 )
    // Returns the string version of milliseconds since
    // Unix epoch then parses into an integer
    @mybluewristband

    View full-size slide

  42. // Date Object
    Date.prototype.toString()
    // e.g. Thu Oct 10 2019 22:46:02
    // GMT-0700 (Pacific Daylight Time)
    Date.prototype.toTimeString()
    // e.g. 22:46:02 GMT-0700
    // (Pacific Daylight Time)
    Date.prototype.toUTCString()
    // e.g. Fri, 11 Oct 2019
    // 05:46:02 GMT
    // Moment.js
    moment().toDate().toString()
    // Translate into a Date object
    // then run .toString() on it
    moment().toDate().toTimeString()
    // Translate into a Date object
    // then run .toString() on it
    moment().utc().format(
    'ddd, DD MMM YYYY HH:mm:ss'
    ) + ' GMT'
    @mybluewristband

    View full-size slide

  43. @mybluewristband
    LOCALE
    STRINGS
    Whoa
    @mybluewristband

    View full-size slide

  44. @mybluewristband
    LOCALE STRINGS
    Super cool!
    // Date Object
    Date.prototype.toLocaleDateString()
    Date.prototype.toLocaleString()
    Date.prototype.toLocaleTimeString()
    // Moment.js
    moment().format('L')
    moment().format('L, LTS')
    moment().format(‘LTS')
    moment().locale()

    View full-size slide

  45. var event = new Date(Date.UTC(2012, 11, 20, 3, 0, 0));
    var options = {
    weekday: ‘long',
    year: ‘numeric',
    month: ‘long',
    day: ‘numeric’
    };
    console.log(event.toLocaleDateString('de-DE', options));
    // expected output: Donnerstag, 20. Dezember 2012
    console.log(event.toLocaleDateString('ar-EG', options));
    // expected output: ٢٠١٢ ،ﺮﺒﻤﺴﯾد ٢٠ ،ﺲﯿﻤﺨﻟا
    console.log(event.toLocaleDateString('ko-KR', options));
    // expected output: 2012֙ 12ਘ 20ੌ ݾਃੌ
    @mybluewristband

    View full-size slide

  46. @mybluewristband

    View full-size slide

  47. @mybluewristband

    View full-size slide

  48. @mybluewristband
    DEPRECATED
    Returned a two digit OR four digit year
    People didn’t think we’d live beyond the
    Mayan calendar
    https://developer.mozilla.org/en-US/
    docs/Web/JavaScript/Reference/
    Global_Objects/Date/getYear
    Date.prototype.getYear()
    Date.prototype.setYear()

    View full-size slide

  49. @mybluewristband
    DEPRECATED
    Converts a date to a string, using Internet
    Greenwich Mean Time (GMT) conventions
    Exact format of the return value varies
    according to the platform and browser…
    https://developer.mozilla.org/en-US/
    docs/Web/JavaScript/Reference/
    Global_Objects/Date/toGMTString
    Date.prototype.toGMTString()

    View full-size slide

  50. @mybluewristband
    NON STANDARD
    Converts a date to a string using the
    specified formatting
    Does not use Intl.DateTimeFormat
    Intl.DateTimeFormat formats dates in
    a standards-compliant way
    Deprecated as of Firefox 58+
    Date.prototype.toLocaleFormat()

    View full-size slide

  51. @mybluewristband
    MOMENT.JS
    A library!
    @mybluewristband

    View full-size slide

  52. @mybluewristband
    ͳͥMOMENT

    View full-size slide

  53. @mybluewristband

    View full-size slide

  54. @mybluewristband
    MORE GETTERS MOMENT.JS OFFERS
    moment().quarter() // Returns the year’s quarter
    moment().weekday() // Returns locale aware day of week
    moment().week() // Returns the week of the year
    moment().dayOfYear() // Returns the number day of the year from 1-366
    moment().weeksInYear() // Returns the number of weeks in a specific year
    moment().unix() // Unix time in seconds

    View full-size slide

  55. @mybluewristband
    DATE TIME MATH IS EASY 1-2-3
    moment().add() // Add to any part(s) of a date
    moment().subtract() // Subtract from any part(s) of a date
    moment().startOf() // Sets any part of a date to the beginning
    moment().endOf() // Sets any part of a date to the end
    moment().local() // Set time to the local time zone
    moment().utc() // Set time to the equivalent UTC time zone
    moment().utcOffset() // Returns the UTC offset in minutes

    View full-size slide

  56. @mybluewristband
    OMG TIMEZONES
    ⚠ ⚠ ⚠ ⚠ ⚠ ) vs &
    @mybluewristband

    View full-size slide

  57. @mybluewristband

    View full-size slide

  58. @mybluewristband
    Docs: https://momentjs.com/timezone/
    Create moments with timezones
    Easily edit those timezones
    MOMENT TIMEZONE
    moment.tz() // Create a moment with a time zone or edit the timezone.
    moment.tz.Zone
    {
    name : 'America/Los_Angeles', // the unique identifier
    abbrs : ['PDT', 'PST'], // the abbreviations
    untils : [1414918800000, 1425808800000], // the timestamps in milliseconds
    offsets : [420, 480] // the offsets in minutes
    }

    View full-size slide

  59. @mybluewristband
    SO, WHAT SHOULD
    WE USE?
    Θ͔Γ·ͤΜʜ

    View full-size slide

  60. @mybluewristband

    View full-size slide


  61. @mybluewristband
    Just use JavaScript until you can't
    anymore!
    Jennifer Wong

    View full-size slide

  62. @mybluewristband
    You’ll

    View full-size slide

  63. @mybluewristband
    BUT DON’T TAKE MY ADVICE
    Do what's best for your team and your need to scale
    @mybluewristband

    View full-size slide

  64. @mybluewristband

    View full-size slide

  65. @mybluewristband
    TEMPORAL
    A tc39 proposal

    View full-size slide

  66. @mybluewristband

    View full-size slide

  67. @mybluewristband

    View full-size slide

  68. @mybluewristband



    View full-size slide

  69. @mybluewristband
    ϓϥεα

    View full-size slide

  70. @mybluewristband
    Zell Liew for CSS Tricks!

    View full-size slide

  71. @mybluewristband

    View full-size slide

  72. @mybluewristband
    ͋Γ͕ͱ͏͟͝
    ͍·ͨ͠ʂ
    ࣭໰
    Jennifer Wong
    @mybluewristband
    https://github.com/jennz0r

    View full-size slide