Luxon: retrieve an array of time offsets and time zones (similar to what can be done in moment-timezone)

Currently, I am using the moment-timezone library to retrieve raw information for a specific timezone and then incorporating it directly into my downstream code.

const zone = moment.tz.zone('Europe/London');

This data contains:

{
    "name":"Europe/London",
    "abbrs":["GMT","BST","GMT","BST", ...],
    "untils":[-1691964000000,-1680472800000,-1664143200000,-1650146400000, ...],
    "offsets":[0,-60,0,-60,0, ...],
    "population":10000000
}

For my purposes, I only require the offsets and untils arrays from moment, as I manage the remaining aspects on my own in the downstream code by utilizing these arrays (or a subset of them)... all without depending on moment.

Is there a similar method to extract the offsets and untils arrays in the luxon library?

Answer №1

After reviewing @VincenzoC's comment, I have come up with a simple approach to calculate offsets and untils (as per the moment-timezone library) for a given time range. This method assumes that offsets change only on the hour, allowing us to iterate through the time range in one-hour increments.

import { IANAZone } from 'luxon';

const getZoneInfo = function (id, startTime, endTime) {
    startTime = Math.floor(startTime / 36e5) * 36e5; // adjust to the previous whole hour
    endTime = Math.ceil(endTime / 36e5) * 36e5;      // adjust to the next whole hour
    const increment = 36e5;                         // one-hour increment
    const zone = IANAZone.create(id);
    const offsets = [];
    const untils = [];
    let offset, prevOffset;
    for (let time = startTime; time <= endTime; time += increment) {
        offset = zone.offset(time);
        if (prevOffset != undefined && offset != prevOffset || time == endTime) {
            offsets.push(-prevOffset);
            untils.push(time);
        }
        prevOffset = offset;
    }
    const zoneInfo = {
        id: id,
        offsets: offsets,
        untils: untils
    };
    console.log('zoneInfo', zoneInfo);
    return zoneInfo;
};

const startTime = 1646931245000;
const endTime = 1650473645000;
getZoneInfo('Europe/London', startTime, endTime);
getZoneInfo('Europe/Stockholm', startTime, endTime);
getZoneInfo('Asia/Tokyo', startTime, endTime);
getZoneInfo('America/New_York', startTime, endTime);

Output:

zoneInfo {
  id: 'Europe/London',
  offsets: [ -0, -60 ],
  untils: [ 1648342800000, 1650474000000 ]
}
zoneInfo {
  id: 'Europe/Stockholm',
  offsets: [ -60, -120 ],
  untils: [ 1648342800000, 1650474000000 ]
}
zoneInfo {
  id: 'Asia/Tokyo',
  offsets: [ -540 ],
  untils: [ 1650474000000 ]
}
zoneInfo {
  id: 'America/New_York',
  offsets: [ 300, 240 ],
  untils: [ 1647154800000, 1650474000000 ]
}

The last until value does not indicate an actual offset change but ensures full coverage of the specified time range up to endTime.

UPDATE

Here is an alternative version of the above code, which aims to be more efficient (especially for larger time ranges) by iterating in full days and switching to hourly increments only when necessary to identify offset changes accurately:

import { IANAZone } from 'luxon';

const getZoneInfo = function (id, startTime, endTime) {
    const zone = IANAZone.create(id);
    const offsets = [];
    const untils = [];
    startTime = Math.floor(startTime / 36e5) * 36e5;   // move to the previous whole hour
    endTime = Math.ceil(endTime / 36e5) * 36e5;        // move to the next whole hour
    const stepSmall = 36e5;                     // one-hour increment
    const stepLarge = 24 * 36e5;                // one-day increment
    let step = stepLarge;                       // start with the larger increment for speed
    let offset, prevOffset, offsetChanged;
    let time = startTime;
    offset = prevOffset = zone.offset(time);
    do {
        time = Math.min(time + step, endTime);
        offset = zone.offset(time);
        offsetChanged = (offset != prevOffset);
        if (offsetChanged || time == endTime) {
            if (offsetChanged && step == stepLarge) {
                // go back and switch to the smaller increment for better transition accuracy...
                time = time - stepLarge;
                step = stepSmall;
                continue;
            } else {
                offsets.push(-prevOffset);
                untils.push(time);
                // revert to the larger increment...
                step = stepLarge;
            }
        }
        prevOffset = offset;

    } while (time < endTime);

    const zoneInfo = {
        id: id,
        offsets: offsets,
        untils: untils
    };
    console.log('zoneInfo', zoneInfo);

    return zoneInfo;
};


const startTime = 1608020493000;
const endTime = 1734250893000;
getZoneInfo('Europe/London', startTime, endTime);
getZoneInfo('Europe/Stockholm', startTime, endTime);
getZoneInfo('Asia/Tokyo', startTime, endTime);
getZoneInfo('America/New_York', startTime, endTime);

Output:

zoneInfo {
  id: 'Europe/London',
  offsets: [
    -0, -60, -0, -60,
    -0, -60, -0, -60,
    -0
  ],
  untils: [
    1616893200000,
    1635642000000,
    1648342800000,
    1667091600000,
    1679792400000,
    1698541200000,
    1711846800000,
    1729990800000,
    1734253200000
  ]
}
zoneInfo {
  id: 'Europe/Stockholm',
  offsets: [
     -60, -120,  -60,
    -120,  -60, -120,
     -60, -120,  -60
  ],
  untils: [
    1616893200000,
    1635642000000,
    1648342800000,
    1667091600000,
    1679792400000,
    1698541200000,
    1711846800000,
    1729990800000,
    1734253200000
  ]
}
zoneInfo {
  id: 'Asia/Tokyo',
  offsets: [ -540 ],
  untils: [ 1734253200000 ]
}
zoneInfo {
  id: 'America/New_York',
  offsets: [
    300, 240, 300,
    240, 300, 240,
    300, 240, 300
  ],
  untils: [
    1615705200000,
    1636264800000,
    1647154800000,
    1667714400000,
    1678604400000,
    1699164000000,
    1710054000000,
    1730613600000,
    1734253200000
  ]
}

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Leveraging the useEffect hook in conjunction with the "async" keyword

Looking for a way to clean up react request in react hooks. I've heard about using AbortController in my hook, but I'm not sure how to implement it. I am currently working with next.js. What are some effective approaches to solve this issue? Also ...

Determine in a JSON array and add to an array object if the key is not found

I've got a JSON array like this: 0: {Id: "1", name: "Adam", Address: "123", userId: "i98"} 1: {Id: "2", name: "John", Address: "456"} The second object in the array doesn't have a userId key. How can I iterate through the array and add the ...

How to incorporate a delay in ng-repeat using AngularJS

Currently, I am facing an issue with my ng-repeat block. In this block, I am generating elements based on data received from an ajax request, which sometimes causes a delay due to latency. Within the same block, I have implemented a filter to remove unwant ...

Running a shared function following every Promise resolution

Currently working on a nodejs project and utilizing bluebird.js for Promises. I'm looking to have a function executed after each .then() method in the chain. Does anyone know of a way or API within bluebird.js that supports this? Appreciate any guida ...

Ways to implement a worldwide change in a subordinate entity

I am facing a challenge where I need to apply a global position, obtained from a WebVR controller, to a child object that is nested within multiple parent objects with transformations. The child object I want to update does not have any transformations app ...

Utilizing Vue.js to retrieve database information and populate input fields through select options

In my Laravel 8 and Vue 3 application, I have a Student Component with a datalist that lists all the students. My goal is to populate the input fields with the specific student information when clicking on a student. I attempted to use Vue select, which i ...

Properties of a child class are unable to be set from the constructor of the parent class

In my current Next.js project, I am utilizing the following code snippet and experiencing an issue where only n1 is logged: class A { // A: Model constructor(source){ Object.keys(source) .forEach(key => { if(!this[key]){ ...

Creating an interactive map on an image using HTML and drawing circles

I've been experimenting with drawing circles on images using the map property in HTML. I have an image set up, and when clicking on the image in JavaScript, I'm adding the area coordinates for the map property. However, I keep encountering a null ...

The TextArea element is experiencing issues with the Jquery function

In my asp.net web application, I have implemented a JQuery function to restrict user input characters. $(document).ready(function () { $('input').on('input', function () { var c = this.selectionStart, ...

Retrieve user information from Auth0 once the user has completed the signup process

I am looking to integrate the ability to create new users on Auth0 through my admin panel. Currently, I am utilizing Auth0 lock for signups, but now I need to store these users in my Database, which requires their email and Auth0 user ID. I am exploring o ...

Check if a specific string is present in an array using JavaScript

When working with SQL, we can easily check if a string is in a list using the following syntax: Column IN ('a', 'b', 'c') But how can we achieve this in JavaScript without it being so cumbersome? if (expression1 || expressi ...

Objects of equal nature combine and sift through

I am looking to categorize objects based on their status ID and also retrieve data and CSR counts for each item. Each StatusName has multiple items: [ { "StatusId": 2, "StatusName": "ordered", " ...

Does embedding an Iframe for external files from your server enhance the loading speed of the current page compared to directly loading it on the page?

I'm facing an issue with the loading time of a Facebook post on my webpage index.php. The current method of using the embedded post provided by Facebook is taking too long to load. My solution is to create a separate page, post.php, where only the Fac ...

The Redux state is not being refreshed

I've been attempting to update the redux store by fetching a list of group names using axios within the action. Despite receiving a response from the API call, the redux store fails to reflect the updated data. FileName: actions/index.js CODE: expo ...

Combine multiple arrays in JavaScript into a single array

Here is the array I am working with: array = ['bla', ['ble', 'bli'], 'blo', ['blu']] I need to transform it into this format: array = ['bla', 'ble', 'bli', 'blo', &a ...

Creating a direct connection between a parent node and all of its children in OrgChartjs

Can I connect all children directly to one parent in Balkan OrgChart.js? This is my starting point based on the documentation of OrgChart.js. window.onload = function () { OrgChart.templates.family_template = Object.assign({}, OrgChart.templates.ana); ...

What is the best method for retrieving the selected itemsPerPage in Vuetify's data-table in version 2.0

Recently, I've been struggling to retrieve the selected items-per-page on a Vuetify data-table due to some recent changes. I came across this helpful example: How to set initial 'rows per page' value in Vuetify DataTable component? Here is th ...

Checking the validity of date inputs - microservice for timestamps

I'm encountering an issue while attempting to validate my date input. I've tried using moment js, but it seems there's a problem. The error message "date invalid" keeps popping up! Here is the code snippet: app.get("/api/timestamp/:date_s ...

Verify all inputs are complete in the FullScreenForm

I have been working on implementing a form from this website: http://tympanus.net/Development/FullscreenForm/ My main objective is to validate each input when the form is submitted and display any errors that may arise. To achieve this, I have already se ...

Defining global 'require' scripts in Node.js

Seeking a solution to a slightly unusual problem. I hope that using simple examples will clarify my query, as explaining my complex usage can be challenging. I am incorporating my custom modules into the routes.coffee file for an Express server. My goal i ...