javascriptdatetimetimezonemomentjsmoment-timezone

MomentJS - Create An ISO 8601 Datetime String In UTC Using Date, Time, And Timezone Variables


I have three separate variables I want to use to construct an ISO 8601 datetime string in UTC (without offsets). The three variables are:

  1. Date (in 2024-7-31 format)
  2. Time (in 14:00 format)
  3. Timezone (can be one of four values - America/New_York, America/Chicago, America/Denver, America/Los_Angeles)

The timezone of the current user (current browser + operating system) should be irrelevant. The user can be in one of the above 4 timezones or any timezone in the world.

I've tried using:

import moment from 'moment';
import 'moment-timezone';

const startDate = '2024-7-31';
const startTime = '14:00';
const startTimezone = 'America/Chicago'
console.log(moment.tz(startDate + ' ' + startTime, startTimezone).utc().format());

The above generates 2024-07-31T14:00:00Z - which equals to 9:00 AM Chicago time on 7-31. The time should be 2:00 PM Chicago time on 7-31. If I change startTimezone to America/New_York, I get the same ISO 8601 result (9:00 AM Chicago time).

From the looks of it, it seems like Moment isn't taking into account the timezone I am feeding it. How do I get Moment to take into account the timezone it is being given?


Solution

  • Here is your code snippet. Run it and you will see the problem immediately.

    const startDate = '2024-7-31';
    const startTime = '14:00';
    const startTimezone = 'America/Chicago'
    console.log(moment.tz(startDate + ' ' + startTime, startTimezone).utc().format());
    <script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.30.1/moment.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.45/moment-timezone-with-data-10-year-range.js"></script>

    Moment's warning is as follows:

    Deprecation warning: value provided is not in a recognized RFC2822 or ISO format. moment construction falls back to js Date(), which is not reliable across all browsers and versions. Non RFC2822/ISO date formats are discouraged.

    Indeed, the string you're parsing "2024-7-31 14:00" is not ISO 8601 compliant, because months are required to be two digits. (It's not RFC2822 compliant either.)

    You can solve this by changing the input date to "2024-07-31".

    const startDate = '2024-07-31';
    const startTime = '14:00';
    const startTimezone = 'America/Chicago'
    console.log(moment.tz(startDate + ' ' + startTime, startTimezone).utc().format());
    <script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.30.1/moment.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.45/moment-timezone-with-data-10-year-range.js"></script>

    Alternatively, you can leave the input date as-is, and supply a format string to Moment:

    const startDate = '2024-7-31';
    const startTime = '14:00';
    const inputFormat = 'YYYY-M-DD H:mm'
    const startTimezone = 'America/Chicago'
    console.log(moment.tz(startDate + ' ' + startTime, inputFormat, startTimezone).utc().format());
    <script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.30.1/moment.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.45/moment-timezone-with-data-10-year-range.js"></script>