primevue icon indicating copy to clipboard operation
primevue copied to clipboard

DatePicker: sets time adjusted to timezone instead of using date only

Open Real-Gecko opened this issue 1 year ago • 13 comments

Describe the bug

I've noticed that when I use DatePicker in model it sets full time with adjustment to timezone instead of putting just date. So if I for example pick 2024-09-05 it'll set 2024-09-04T19:00:00.000Z in model and it'll be sent to the server. Is it possible to set only date like <input type="date"/> does?

Reproducer

https://stackblitz.com/edit/primevue-4-ts-vite-issue-template-csnodp

PrimeVue version

4.0.5

Vue version

4.x

Language

TypeScript

Build / Runtime

Vite

Browser(s)

No response

Steps to reproduce the behavior

No response

Expected behavior

No response

Real-Gecko avatar Sep 05 '24 08:09 Real-Gecko

Same issue here I got really confused when inputting 09/11/2024 and seeing that when pushing my form the date is 2024-09-10T22:00:00.000Z No transformations on my part prior to POSTing my form

<DatePicker v-model="form.deadline_date" />

PrimeVue version

^4.0.0

Vue version

3.2.x

Language

Javascript

Build / Runtime

Vite

AnthonyBerisha avatar Sep 10 '24 15:09 AnthonyBerisha

My current solution looks like this:

<script setup lang="ts">
import DatePicker from "primevue/datepicker"
import { inject, ref } from "vue"

const data: any = inject("data")
const errors: any = inject("errors")

const props = defineProps<{
  label: string
  name: string
}>()

const value = ref(
  data.value[props.name] ? new Date(data.value[props.name]) : undefined
)

function setDate(date: Date) {
  data.value[props.name] = date.toLocaleDateString`en-CA`
}
</script>

<template>
  <DatePicker
    class="form-control"
    :class="{ 'is-invalid': name in errors }"
    v-model="value"
    :invalid="errors[name]"
    size="small"
    date-format="dd.mm.yy"
    @update:model-value="setDate"
  />
</template>

So instead of passing data object directly to DatePicker's v-model I use setDate method to update ref which stores the data being sent to server.

Real-Gecko avatar Sep 10 '24 16:09 Real-Gecko

Having the same Problem, I don't find a way to configure the right timezone to output. I select a date like 2024-11-25 but i get 2024-11-24T23:00:00.000Z

FinnThorwarth avatar Nov 25 '24 11:11 FinnThorwarth

@cagataycivici any solution please

CodeOutput avatar Nov 28 '24 10:11 CodeOutput

Note that this issue arises when the model value is set to a string instead of a Date. When the model value is a Date as it should be, you can then format it however you like.

matf avatar Dec 25 '24 11:12 matf

Note that this issue arises when the model value is set to a string instead of a Date. When the model value is a Date as it should be, you can then format it however you like.

I have not had this experience. On my setup it does this whether its a Date object or a string.

taylordragoo avatar Feb 27 '25 13:02 taylordragoo

Same problem, and it looks extremely wrong, forcing extra processing of dates from each field. I am using Date object as a value.

VirtualZer0 avatar Mar 21 '25 07:03 VirtualZer0

I really wish that the DatePicker would let you pick dates. Not DateTime.

side note: shame on js for miss-naming Date.js

maartenderie avatar Mar 24 '25 14:03 maartenderie

Same problem here, will any correction be applied to this case?

RogerPelissoni avatar May 26 '25 13:05 RogerPelissoni

Indeed, this is extremely confusing, especially since I always get the day before what i select, due to timezone shenanigans. Threw me for a loop for a few hours there, and I'm unsure how best to fix this without a bunch of spaghetti code everywhere to account for this.

cryogenfx avatar May 27 '25 05:05 cryogenfx

It would be great to be able to either explicitly specify a UTC timezone on DatePicker or otherwise allow a "date only" pick mode that also omits the timezone somehow. Having to do a lot of extra processing and wrap all DatePickers in a custom component right now.

james-onpoint avatar Jun 08 '25 11:06 james-onpoint

I'm having the same issue. Very frustrating bug. I made this wrapper component to resolve it. I haven't thoroughly tested, so use at your own caution:

<script setup lang="ts">

import { defineModel, defineProps, defineEmits, computed, useAttrs } from 'vue'
import DatePicker, { type DatePickerProps, type DatePickerSlots, type DatePickerEmits } from 'primevue/datepicker';
import { format } from 'date-fns'

const model = defineModel();
const attrs = useAttrs()
interface Props extends /* @vue-ignore */ DatePickerProps {}
const props = defineProps<Props>()
interface Slots extends /* @vue-ignore */ DatePickerSlots {}
defineSlots<Slots>();
interface Emits extends /* @vue-ignore */ DatePickerEmits {}
defineEmits<Emits>();

const computedValue = computed({
  get() {
    if (attrs.showTime){
        return model.value
    }
    if (model.value !== undefined) {
        if (attrs?.selectionMode == 'multiple'){
            return (model.value as []).map(v=>convertToLocalDate(v))
        }
      return convertToLocalDate(model.value as any)
    }
    return null
  },
  set(value: Date | null) {
    const dateStr = convertToDateString(value)
    model.value = dateStr

  }
})

function convertToLocalDate(dateValue: string | Date | null): Date | null {
  if (!dateValue) return null
  
  // If it's already a Date object, return it
  if (dateValue instanceof Date) return dateValue
  
  // If it's a date string like "2025-06-09", create a local date to avoid timezone issues
  if (typeof dateValue === 'string' && dateValue.match(/^\d{4}-\d{2}-\d{2}$/)) {
    const [yearStr, monthStr, dayStr] = dateValue.split('-')
    return new Date(parseInt(yearStr), parseInt(monthStr) - 1, parseInt(dayStr))
  }
  
  // For other string formats, try to parse normally
  if (typeof dateValue === 'string') {
    return new Date(dateValue)
  }
  
  return null
}

function convertToDateString(value: Date | null): string | null {
  if (!value) return null
  
  // Convert Date object back to YYYY-MM-DD string format
  return format(new Date(value), 'yyyy-MM-dd')
}

const computedProps = computed(()=>({...props, 'modelValue': computedValue}))



</script>

<template>
    <DatePicker v-bind="(computedProps as any)">
       
      <template v-for="(_, slotName) in $slots" v-slot:[slotName]="slotProps">
        <slot :name="slotName" v-bind="slotProps ?? {}" />
      </template>
    </DatePicker>
  </template>

cory-weiner avatar Jun 12 '25 15:06 cory-weiner

Has anyone solved this? annoying

GuilhermeLimaSP avatar Jun 14 '25 03:06 GuilhermeLimaSP

This issue is too important not to be solved by now!

ShiferawAbel avatar Jul 04 '25 09:07 ShiferawAbel

Still waiting for a solution...

jvelten avatar Aug 01 '25 07:08 jvelten

It's very annoying indeed to have to deal with javascript Date objects whereas the standard HTML input type="date" control deals with text, especially when you want the DatePicker to work only for dates and not full date and time.

As for the timezone issue, my current "hack" is to bypass the v-model directive and use :model-value and @value-change emit to build a new Date with the offset removed, so that it can easily be converted to a "date only" afterwards:

const myDate = ref<Date>()

[...]

<DatePicker
    :model-value="myDate"
    @value-change="(e: any) => myDate = new Date(e.getTime() - e.getTimezoneOffset() * 60000)"
/>

{{ myDate?.toISOString().slice(0, 10) }}

NikoGJ avatar Aug 05 '25 09:08 NikoGJ

@cagataycivici merhaba; sorunla neden ilgilenmiyorsunuz. Sizden satın altığımız themeda da benzer sorunlar var. Teşekkürler

CodeOutput avatar Aug 16 '25 15:08 CodeOutput

This issue among many others overlooked for years yet highlighted by community is the reason I'm currently waiting for NuxtUI to get free instead of buying Prime's figma kit.

KazimirPodolski avatar Sep 23 '25 00:09 KazimirPodolski

We've decided to add dataType prop as in PrimeNG, default to Date and setting it string provides what is displayed value in formatted form.

@mertsincan @tugcekucukoglu please take over.

cagataycivici avatar Sep 23 '25 15:09 cagataycivici

Thank you for this! @tugcekucukoglu one console.log sneaked into the commit ;)

Mettbrot avatar Sep 29 '25 06:09 Mettbrot

Thanks for the update !

We were also annoyed by this behavior.

Waiting for 4.4.0 release...

franck-grenier avatar Sep 30 '25 14:09 franck-grenier

@tugcekucukoglu using the just released Version 4.4.0 updateModelType is mandatory in DatePickerProps. Was that intentional?

error TS2345: Argument of type '{ modelValue: Date | Date[] | undefined; dateFormat: string; placeholder: string; 'onUpdate:modelValue': any; }' is not assignable to parameter of type 'DatePickerProps & VNodeProps & AllowedComponentProps & ComponentCustomProps & Record<string, unknown>'.
  Property 'updateModelType' is missing in type '{ modelValue: Date | Date[] | undefined; dateFormat: string; placeholder: string; 'onUpdate:modelValue': any; }' but required in type 'DatePickerProps'.

80         <DatePicker
            ~~~~~~~~~~

  node_modules/.pnpm/[email protected][email protected][email protected]_/node_modules/primevue/datepicker/index.d.ts:545:5
    545     updateModelType: HintedString<'date' | 'string'> | undefined;
            ~~~~~~~~~~~~~~~
    'updateModelType' is declared here.

Mettbrot avatar Oct 02 '25 09:10 Mettbrot

The problem is that it shows the user the local time but behind the scene it works with UTC time. you should always check for offset between your localtime and utctime when sending the data to server. example:

const now = Date.now();
const offsetMinutes = new Date().getTimezoneOffset();
const timeToBeSent = new Date(now + offsetMinutes * 60 * 1000)

alemkhodadadi-solgeo avatar Nov 06 '25 11:11 alemkhodadadi-solgeo