Time zones and daylight-saving time (DST)

When a plan spans over multiple time zones, or DST change occurs, local time is no longer reliable.

1. Multiple time zones

It takes 8 minutes to drive from Ranburne (Alabama) to Bowdon (Georgia), but these towns are in different timezones: Ranburn in Central Time (CT) and Bowdon in Eastern Time (ET).

Gus is running a shift around Ranburne (Alabama) in Central Time (UTC-6 in winter):

  • The first visit is planned in Ranburne from 2024-03-01T10:00:00-6 to 2024-03-01T12:00:00-6.

  • The second visit is located in Bowdon (Georgia) and planned for Gus for 2024-03-01T13:00:00-6 to 2024-03-01T15:00:00-6.

  • Despite being only 8-minute drive away from Ranburne, Bowdon operates under Eastern Time (UTC-5 in winter). The Bowdon customer is available from 2024-03-01T09:00:00-5 to 2024-03-01T17:00:00-5 ET. This translates to Gus as 2024-03-01T08:00:00-6 to 2024-03-01T16:00:00-6 CT.

  • Gus can confirm to his customer that he will be performing the job from 2024-03-01T14:00:00-5 to 2024-03-01T16:00:00-5 ET.

gus time zones

Using plain local date time can create not only a misunderstanding between Gus and the customer but also result in an unrealistic plan:

Beth is running a shift in UTC-4 time zone (New York):

  • First of the visits to be planned is in the same time zone with the availability window from 2024-03-01T08:00:00 to 2024-03-01T09:30:00.

  • The second visit has the same local availability window from 2024-03-01T08:00:00 to 2024-03-01T09:30:00, but this time in UTC-5.

Using only local date time incorrectly prevents both visits from being assigned to Beth.

beth time zones

Using offset datetime or UTC resolves the above problems.

1.1. Using local date time with offset to UTC

Let’s replace all local date time values by ISO 8601 local date time with offset to UTC, such as 2024-03-01T08:00:00-4 for UTC-4.

  • Input

  • Output

{
   ...
   "shifts": [
       {
        "minStartTime": "2024-03-01T08:00:00-4",
        "maxEndTime": "2024-03-01T16:00:00-4",
        ...
       }
   ],
   "visits": [
       {
        "id": "Visit A",
        "serviceDuration": "PT45M",
        "timeWindows": [
          {
            "minStartTime": "2024-03-01T08:00:00-4",
            "maxEndTime": "2024-03-01T09:30:00-4"
          }
        ]
       },
       {
        "id": "Visit B",
        "serviceDuration": "PT45M",
        "timeWindows": [
          {
            "minStartTime": "2024-03-01T08:00:00-5",
            "maxEndTime": "2024-03-01T09:30:00-5"
          }
        ]
       }
   ]
}
{
   ...
   "shifts": [
       {
        "startTime": "2024-03-01T08:00:00-4",
        "itinerary": [
          {
            "id": "Visit A",
            "arrivalTime": "2024-03-01T08:45:00-4",
            "startServiceTime": "2024-03-01T08:45:00-4",
            "departureTime": "2024-03-01T09:30:00-4",
            "effectiveServiceDuration": "PT45M",
            ...
          },
          {
            "id": "Visit B",
            "arrivalTime": "2024-03-01T09:45:00-4",
            "startServiceTime": "2024-03-01T09:45:00-4",
            "departureTime": "2024-03-01T10:30:00-4",
            "effectiveServiceDuration": "PT45M",
            ...
          }
        ],
        ...
       }
   ]
}
Please note that the output itinerary uses the offset of the shift start time for all itinerary items (visits and breaks) to provide consistent time zone information from the vehicle shift perspective. In the example above, the arrivalTime, startServiceTime and departureTime for Visit B have the -4 offset (the same as the shift’s startTime).
The client is expected to interpret all offset date times according to the rules of the relevant time zone (different time zones might be relevant for different parts of a vehicle shift route, for instance).

1.2. Using local date time converted to UTC

Another option is to convert all the date times into UTC time zone (offset Z representing +0). For example, 2024-03-01T08:00:00-4 in UTC-4 will be converted into 2024-03-01T12:00:00Z.

This might be handy if you need to integrate with other backend systems already using UTC, or if you prefer to avoid using different offsets.

Let’s take a look at the same example, this time represented in UTC:

  • Input

  • Output

{
   ...
   "shifts": [
       {
        "minStartTime": "2024-03-01T12:00:00Z",
        "maxEndTime": "2024-03-01T20:00:00Z",
        ...
       }
   ],
   "visits": [
       {
        "id": "Visit A",
        "serviceDuration": "PT45MH",
        "timeWindows": [
          {
            "minStartTime": "2024-03-01T12:00:00Z",
            "maxEndTime": "2024-03-01T13:30:00Z"
          }
        ]
       },
       {
        "id": "Visit B",
        "serviceDuration": "PT45M",
        "timeWindows": [
          {
            "minStartTime": "2024-03-01T13:00:00Z",
            "maxEndTime": "2024-03-01T14:30:00Z"
          }
        ]
       }
   ]
}
{
   ...
   "shifts": [
       {
        "startTime": "2024-03-01T12:00:00Z",
        "itinerary": [
          {
            "id": "Visit A",
            "arrivalTime": "2024-03-01T12:45:00Z",
            "startServiceTime": "2024-03-01T12:45:00Z",
            "departureTime": "2024-03-01T13:30:00Z",
            "effectiveServiceDuration": "PT45M",
            ...
          },
          {
            "id": "Visit B",
            "arrivalTime": "2024-03-01T13:45:00Z",
            "startServiceTime": "2024-03-01T13:45:00Z",
            "departureTime": "2024-03-01T14:30:00Z",
            "effectiveServiceDuration": "PT45M",
            ...
          }
        ],
        ...
       }
   ]
}
The client is expected to interpret all offset date times according to the rules of the relevant time zone (different time zones might be relevant for different parts of a vehicle shift route, for instance).

2. Daylight Saving Time (DST)

Imagine Carl having an overnight shift during the DST change to summer time. Carl’s second visit in the itinerary, Visit B, is supposed to end at 02:45. However, at 02:00 local time, the clock jumps one hour forward to 03:00 and the rest of the plan for the shift is ruined, Carl will always be behind the plan. By the time when he finishes Visit B, he is supposed to be already nearly finishing Visit C.

Similar situation happens during DST change to winter time, except that at 03:00 the clock goes one hour back and Carl is in fact granted an extra hour which was not in the plan. Carl can cope with it by waiting which is a waste of both Carl’s and his employer’s time.

daylight saving time

Using offset datetime or UTC resolves the above problems.

2.1. Using local date time with offset to UTC

Let’s replace all local date time values by ISO 8601 local date time with offset to UTC, such as 2024-03-10T01:00:00-5 for New York winter time. During the DST change to summer time, the offset changes from -5 to -4:

  • Input

  • Output

{
   ...
   "shifts": [
       {
        "minStartTime": "2024-03-09T22:00:00-5",
        "maxEndTime": "2024-03-10T06:00:00-4",
        ...
       }
   ],
   "visits": [
       {
        "id": "Visit B",
        "serviceDuration": "PT1H",
        "timeWindows": [
          {
            "minStartTime": "2024-03-10T01:30:00-5",
            "maxEndTime": "2024-03-10T04:00:00-4"
          }
        ]
       }
   ]
}
Please note the maxEndTime value in the example. You can decide how to deal with the DST change and the shift duration: 2024-03-10T06:00:00-4 means that Carl works for 7 hours and ends at 06:00 in the morning; 2024-03-10T07:00:00-4 means that Carl keeps his 8 working hours at the cost of ending at 07:00 instead of 06:00.
{
   ...
   "shifts": [
       {
        "startTime": "2024-03-09T22:00:00-5",
        "itinerary": [
          {
            "id": "Visit B",
            "arrivalTime": "2024-03-10T01:45:00-5",
            "startServiceTime": "2024-03-10T01:45:00-5",
            "departureTime": "2024-03-10T02:45:00-5",
            "effectiveServiceDuration": "PT1H",
            ...
          }
        ],
        ...
       }
   ]
}
Please note that the output itinerary uses the offset of the shift start time even after DST change (departureTime in this example). Even though the offset does not reflect the DST change, it represents the correct time instant.
The client is expected to interpret all offset date times according to the rules of the relevant time zone (different time zones might be relevant for different parts of a vehicle shift route, for instance).

2.2. Using local date time converted to UTC

Another option is to convert all the date times into UTC time zone (offset +0 or Z). For example, 2024-03-10T01:00:00-5 in New York winter time will be converted into 2024-03-10T06:00:00Z.

This might be handy if you need to integrate with other backend systems already using UTC, or if you prefer to avoid using different offsets.

Let’s take a look at the same example, this time represented in UTC:

  • Input

  • Output

{
   ...
   "shifts": [
       {
        "minStartTime": "2024-03-10T03:00:00Z",
        "maxEndTime": "2024-03-10T10:00:00Z",
        ...
       }
   ],
   "visits": [
       {
        "id": "Visit B",
        "serviceDuration": "PT1H",
        "timeWindows": [
          {
            "minStartTime": "2024-03-10T06:30:00Z",
            "maxEndTime": "2024-03-10T08:00:00Z"
          }
        ]
       }
   ]
}
Again, please note the maxEndTime value in the example. You can decide how to deal with the DST change and the shift duration: plain conversion of 2024-03-10T06:00:00-4 into UTC 2024-03-10T10:00:00Z means that Carl works for 7 hours; if desired, you can add an extra hour to get 2024-03-10T11:00:00Z meaning that Carl keeps his 8 working hours.
{
   ...
   "shifts": [
       {
        "startTime": "2024-03-10T03:00:00Z",
        "itinerary": [
          {
            "id": "Visit B",
            "arrivalTime": "2024-03-10T06:45:00Z",
            "startServiceTime": "2024-03-10T06:45:00Z",
            "departureTime": "2024-03-10T07:45:00Z",
            "effectiveServiceDuration": "PT1H",
            ...
          }
        ],
        ...
       }
   ]
}
The client is expected to interpret all offset date times according to the rules of the relevant time zone (different time zones might be relevant for different parts of a vehicle shift route, for instance).