Skip to content

Incorrect date returned using date only picker and going from non-DST to DST date #1112

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
adamreisnz opened this issue Mar 27, 2025 · 5 comments
Labels
bug Something isn't working

Comments

@adamreisnz
Copy link

adamreisnz commented Mar 27, 2025

Describe the bug
When the datepicker is initialized with a date that falls within DST, and the user then selects a date that falls outside of DST, the picker will incorrectly select one day early.

To Reproduce
Failing example (v11.0.2) – https://stackblitz.com/edit/vuepic-vue-datepicker-rxa4wute

Steps to reproduce the behavior:

  1. Change your local computer's timezone to Pacific/Auckland
  2. Observe the date picker is initialized on 27-03-2025 (which is in DST in the specified timezone)
  3. Click on the date picker
  4. Select 27 DECEMBER 2025
  5. Observe that the date picks selects 26 DECEMBER 2025 instead
  6. Observe that the local reported date is 12/26/2025, 11:00:00 PM instead of 12/27/2025, 00:00:00

Expected behavior
The datepicker should select 27 DECEMBER 2025 when the user clicks on 27 DECEMBER 2025

I would personally expect that when not using the time picker, the dates returned would always return as a midnight timestamp on the selected date in the specified timezone.

If not using the timepicker, the user doesn't care about the time portion and is just interested in a date. So we should get the expected date in all circumstances, and not have it be dependent on what previous date was selected.

Edit: It seems this problem mainly occurs when your system timezone is not in the same timezone as the one you're testing with. However, Datepicker should respect the timezone provided as input prop.

Screenshots
Image

Desktop & mobile (please complete the following information):

  • Chrome
  • 11.0.2
@adamreisnz adamreisnz added awaiting triage The issue is not reviewed by the maintainers bug Something isn't working labels Mar 27, 2025
@rajmondx
Copy link

rajmondx commented Apr 2, 2025

I just noticed the same issue now that Europe is in Summer Time (which started on March 30, 2025).

Vue Datepicker uses the current offset, which is +2 during Summer but +1 in Winter. This means that if I pick a Winter date (e.g., December) while in Summer, the offset applied is still +2, even though it should be +1 for Winter.

I suggest to use https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal so vue-datepicker would not have to care about timezone conversion. There are currently two polyfills available. One is from the original proposers and the other one claims to be more performant, using less space while being compatible with the specs.

@adamreisnz
Copy link
Author

What I think might be a simple solution, is then the DatePicker is configured to not show time selection, it ensures that every timestamp/date returned, is always at midnight in whatever timezone/DST/non-DST that specific selected date might be.

Fix we currently have to use (we convert the incoming Date object to a Luxon DateTime instance:

const convertJSDateToDateTime = date => {
  const dateTime = DateTime.fromJSDate(date, {zone: timezone.value})
  const hour = dateTime.hour
  const modifiedDate = hour === 23 ? dateTime.plus({hours: 1}) : dateTime
  return modifiedDate
    .startOf('day')
    .setZone('utc')
}

@rajmondx
Copy link

rajmondx commented Apr 3, 2025

I agree, but currently, JavaScript can only handle dates using the Date object. There are no dedicated data types for "only time" or "only date," which is why the Temporal API was introduced and will be natively added to ECMAScript. This will bring new types like PlainTime and PlainDate. You can read more about it here: [TC39 Temporal Proposal](https://tc39.es/proposal-temporal/docs/). You can also experiment there with Temporal in the JavaScript console.

My Current Workaround

I avoid letting vue-datepicker handle time zones and instead manage them manually.

      :readonly="isReadonly"
      :clearable="clearable && !isReadonly && !isDisabled"
-      :timezone="getTimeZoneIdDisplay()"
      @update:model-value="closePicker()"
    />

I need to account for two time zones:

  1. The time zone in which the date is originally provided.
  2. The time zone in which the date is displayed.

The date picker always receives a full ISO date (i.e., an Instant, such as 2025-04-03T04:35:46.726Z), but the actual date representation can vary—for example, using PlainDate (2025-04-03).

const isoDateType: IsoDateType = getIsoDateType(model.value)
    if (isoDateType != composedProps.type) {
      logger.warn(
        `Value (${model.value}) has different isoDateType (${isoDateType}) than props (${composedProps.type}), the date will be returned as defined in props (${composedProps.type})`
      )
    }
    if (isoDateType == 'PlainDate') {
      return (
        PlainDate.from(model.value)
          .toZonedDateTime(getTimeZoneIdModel())
          .toInstant()
          .toString({
            timeZone: getTimeZoneIdDisplay()
          })
      )
    }
    if (isoDateType == 'PlainDateTime') {
      return (
        PlainDateTime.from(model.value)
          .toZonedDateTime(getTimeZoneIdModel())
          .toInstant()
          .toString({
            timeZone: getTimeZoneIdDisplay()
          })
      )
    }
    // is Instant/ZonedDateTime (contains Timezone already)
    return Instant.from(model.value).toString({
      timeZone: getTimeZoneIdDisplay()
    })

@RiesvGeffen
Copy link

With CEST, that has been applied recently, we see the same issue in our application. Any simple workaround found or bugfix planned?

@adamreisnz
Copy link
Author

See my comment above for a simple non-Vue datepicker workaround:
This uses Luxon, but can easily be adapted.

const convertJSDateToDateTime = date => {
  const dateTime = DateTime.fromJSDate(date, {zone: timezone.value})
  const hour = dateTime.hour
  const modifiedDate = hour === 23 ? dateTime.plus({hours: 1}) : dateTime
  return modifiedDate
    .startOf('day')
    .setZone('utc')
}

@Jasenkoo Jasenkoo removed the awaiting triage The issue is not reviewed by the maintainers label Apr 8, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

4 participants