iamkun / dayjs

⏰ Day.js 2kB immutable date-time library alternative to Moment.js with the same modern API
https://day.js.org
MIT License
47.07k stars 2.31k forks source link

day.js default timezone problem #1227

Open ruffryder opened 4 years ago

ruffryder commented 4 years ago

Hi there. I am having trouble in the following scenario: When I set the default timezone, using dayjs.tz.setDefault("America/New_York") and then create new object using the dayjs() constructor, the newly created object does not have the timezone set. The only way to have timezone on the object is by using the dayjs.tz() constructor, but in this case the expected arguments are completely different. So, is there a way to set default timezone and be able to create objects with the standart constructor with the default timezone set? Code example: dayjs.tz.setDefault("America/New_York");

dayjs("20/11/2020","DD/MM/YYYY"); // This object does not have the default timezone set

dayjs.tz(); //Here, we have the default timezone set to America/New_York

iamkun commented 4 years ago

dayjs.tz.setDefault only affect dayjs.tz at present

ruffryder commented 4 years ago

So, does that mean that there's no way to create an object with the default timezone in the standard way (with dayjs() constructor)?

iamkun commented 4 years ago

Well, as for now, NO. We can only set default tz in dayjs.tz.

Feel free to open a PR if you need this.

Pixelatex commented 3 years ago

Can we atleast add this to the docs to clarify this? Spent quite searching for a weak bug that turns out to be caused by this.

bene-we commented 3 years ago

Also went looking for this, found the doc entry after quite a while under https://day.js.org/docs/en/timezone/set-default-timezone. Still +1 for this.

Kotoriii commented 3 years ago

Would love to have this as well

hisuwh commented 3 years ago

The notice here is really unclear: Notice: dayjs.tz.setDefault will not affect existing dayjs objects. This sounds to me like:

const value1 = dayjs("2021-05-18T14:44:00.000Z");

dayjs.tz.setDefault("Etc/UCT"); 

const value2 = dayjs("2021-05-18T14:44:00.000Z");

// value1 is an "existing dayjs object" so I would not expect it have the timezone.
const result = value1.format("DD/MM/YYYY HH:mm") === value2.format("DD/MM/YYYY HH:mm");
// would expect result to be false but actually true
aagamdoshi commented 3 years ago

@hisuwh Even I found this notice very unclear. Hoping for a cleaner description

mrdulin commented 3 years ago

+1, What does Notice: dayjs.tz.setDefault will not affect existing dayjs objects. exactly mean? Please add an example for the documentation.

jemink commented 3 years ago

facing the same issue with dayjs. In my current project I want to display all the date as per the login user time zone. So for that I am passing the user timezone in backend with header value and inside the backend I am setting default time zone with user time zone. Then after inside my code I used dayjs() and it was not use the setDefault timezone it use local timezone.

iamkun commented 3 years ago

At preset, setDefaultTimezone will only affect dayjs.tz() not dayjs()

e.g.

dayjs.tz.setDefault("America/New_York")

dayjs.tz("2014-06-01 12:00")  // The same behavior with dayjs.tz("2014-06-01 12:00", "America/New_York")

dayjs("2014-06-01 12:00")  // Still local timezone

But I'm thinking, seems it's better to make setDefaultTimezone a global default timezone. That is to say, dayjs() will also use the updated default timezone.

Just wondering if anyone is interested to make a PR to fix this?

ycjcl868 commented 3 years ago

Is there any progress?

cmcnamara87 commented 3 years ago

I ended up doing this

import dayjs from 'dayjs';
import utc from 'dayjs/plugin/utc';
import timezone from 'dayjs/plugin/timezone';

dayjs.extend(utc);
dayjs.extend(timezone);
dayjs.tz.setDefault('Australia/Sydney');

export default dayjs.tz;

and replacing all my imports import dayjs from './dayjs'

madhurgarg71 commented 3 years ago

I ended up doing this

import dayjs from 'dayjs';
import utc from 'dayjs/plugin/utc';
import timezone from 'dayjs/plugin/timezone';

dayjs.extend(utc);
dayjs.extend(timezone);
dayjs.tz.setDefault('Australia/Sydney');

export default dayjs.tz;

and replacing all my imports import dayjs from './dayjs'

@cmcnamara87 This works, but after doing this I am unable to see the autosuggestion for dayjs apis like .add(), ..subtract() etc. possibly because of the missing type definitions on dayjs.tz. Are you also facing the same or were you able to do something about it?

KonstantinZhukovskij commented 2 years ago

Any news here?

ven commented 2 years ago

any updates on this?

Alex-Pqn commented 2 years ago

Update or still nothing ?

marnixhoh commented 2 years ago

For what it's worth: I just migrated a code base from moment to day.js and I too ran into this issue. The behavior of the two libraries differs here.

moment applies the default timezone to all instances --> applies to both moment() & moment.tz() day.js applies the default timezone to only dayjs.tz()

joelstein commented 2 years ago

I also encountered this.

Switching to day.js from moment.js, I expected that dayjs.tz.setDefault() would affect all dayjs() instances.

As others mentioned, the documentation doesn't clearly explain the difference.

Time to find all dayjs( and replace with dayjs.tz(.

merajseraji commented 2 years ago

I ended up doing this

import dayjs from 'dayjs';
import utc from 'dayjs/plugin/utc';
import timezone from 'dayjs/plugin/timezone';

dayjs.extend(utc);
dayjs.extend(timezone);
dayjs.tz.setDefault('Australia/Sydney');

export default dayjs.tz;

and replacing all my imports import dayjs from './dayjs'

@cmcnamara87 This works, but after doing this I am unable to see the autosuggestion for dayjs apis like .add(), ..subtract() etc. possibly because of the missing type definitions on dayjs.tz. Are you also facing the same or were you able to do something about it?

this works for me. with this code also you can use autoseffestion for daujs apis : dayjs.extend(utc); dayjs.extend(timezone); dayjs.tz.setDefault("Asia/Tehran"); static dayjs(): Dayjs { return dayjs.tz(dayjs()) as Dayjs; }

and then use this.dayjs() anywhere.

hisuwh commented 2 years ago

globals...🤢

crobinson42 commented 2 years ago

I like how axios lib allows creating an instance via const authApi = axios.create({ ... }); const publicApi = axios.create({ ... });.

dayjs should do something similar:

const asiaTehranDayjs = dayjs.instance().tz.setDefault('Asia/Tehran')

Also, another really great convenience that others have pointed out (@marnixhoh comment) would be to also automatically apply the default timezone so it's not necessary to call dayjs().tz().format() etc..

CaM2091 commented 2 years ago

You can create a service like this

// Filename : dayjs.ts

import dayjs from "dayjs";
import utc from "dayjs/plugin/utc";
import timezone from "dayjs/plugin/timezone";
import "dayjs/locale/fr";

dayjs.extend(utc);
dayjs.extend(timezone);
dayjs.locale("fr");

dayjs.tz.setDefault("Europe/Paris")

const timezonedDayjs = (...args: any[]) => {
    return dayjs(...args).tz();
};

const timezonedUnix = (value: number) => {
    return dayjs.unix(value).tz();
};

timezonedDayjs.unix = timezonedUnix;
timezonedDayjs.duration = dayjs.duration;

export default timezonedDayjs;

And change your import from import dayjs from "dayjs" to import dayjs from "my-service/dayjs" With this, typing works even with plugins

mishanianod commented 1 year ago

Hi, default timezone is needed on the dayjs

andrew-atwood-infinitusai commented 1 year ago

The underlying problem here is that there's no way for the plug-in to update the constructor called by the main dayjs factory function, so it's impossible for the timezone plug-in to work that way.

If plug-ins could each initialize functions that the constructor would iterate through and call, it would make the desired behavior possible.

maordaniel commented 1 year ago

Another issue with Day.js's timezone functionality is that when a date without a timestamp is passed, Day.js will calculate a default timestamp and then apply the timezone to it, which can cause the date to advance by a day if the timezone is positive.

dayjs.tz.setDefault("Africa/Addis_Ababa") moment.tz.setDefault("Africa/Addis_Ababa")

const aDate = "2023-02-06"

const dayjsDate = dayjs(aDate).tz().format("MMM DD, YYYY") const momentDate = moment(aDate).format("MMM DD, YYYY")

dayjsDate eq to "Feb 27, 2023" momentDate eq to "Feb 26, 2023"

Anubarak commented 1 year ago

Could you at least make a setting that somehow makes it unable to create dayjs objects? or a setting that requires the local for all dayjs objects?

I was about to switch to dayjs but I know me - even if there is a service and I do always use my custom dayjs service - there will be the day in a few years where I or others in my team will most certainly forget it and import the normal dayjs function and no-one will notice it - since everything works for us.

using dayjs.tz() over dayjs() is just so inconvinient in my opinion - most people with several projects that use dayjs() 95% of the time will forget it, when they hop into the one project that requires dayjs.tz()

EgorKluch commented 1 year ago

Could you at least make a setting that somehow makes it unable to create dayjs objects? or a setting that requires the local for all dayjs objects?

I was about to switch to dayjs but I know me - even if there is a service and I do always use my custom dayjs service - there will be the day in a few years where I or others in my team will most certainly forget it and import the normal dayjs function and no-one will notice it - since everything works for us.

using dayjs.tz() over dayjs() is just so inconvinient in my opinion - most people with several projects that use dayjs() 95% of the time will forget it, when they hop into the one project that requires dayjs.tz()

And daysjs.tz doesn't have strict flag.

justingolden21 commented 11 months ago

I'm running into an issue where only GMT+0 (London) doesn't work, but every other timezone works fine... I think it's related to this issue in dayjs as I have no specific code for that case.

justingolden21 commented 11 months ago

dayjs($now).tz('Etc/GMT').locale( 'en').format('h:mm A')

INCORRECT time: 1:36pm

dayjs($now).tz('Etc/GMT').format('h:mm A') (without locale)

CORRECT time: 5:36pm

This bug is only present if the timezone is 'Etc/GMT' (or 'Europe/London') and works fine in 'Etc/GMT+1' and 'Etc/GMT-1' with locale set.

h0gar commented 9 months ago

My solution:

const dayjstz = (...args) => dayjs(...args).tz("Europe/Paris", true);
for(let k of Object.getOwnPropertyNames(dayjs)) {
  if(k === 'unix')
    dayjstz.unix = (...args) => dayjs.unix(...args).tz();
  else
    dayjstz[k] = (...args) => dayjs[k](...args);
}
dayjstz.dayjs = dayjs;

module.exports = dayjstz
dominikbrazdil commented 8 months ago

dayjs($now).tz('Etc/GMT').locale( 'en').format('h:mm A')

INCORRECT time: 1:36pm

dayjs($now).tz('Etc/GMT').format('h:mm A') (without locale)

CORRECT time: 5:36pm

This bug is only present if the timezone is 'Etc/GMT' (or 'Europe/London') and works fine in 'Etc/GMT+1' and 'Etc/GMT-1' with locale set.

I experience the same issue

bmg-will commented 8 months ago

We ran into this issue recently due to not spotting the warning in the docs and assumed it would default the tz for all new dayjs objects.

We fixed it by doing the below in case it helps anyone with this issue -

import dayjsImport from 'dayjs';

// various .extend method calls to dayJsImport here

const dayjs = (date?: dayjsImport.ConfigType, format?: dayjsImport.OptionType) => {
  const instance = dayjsImport(date, format);
  instance.tz('Europe/London');
  return instance;
};

dayjs.isDayjs = dayjsImport.isDayjs;
// make sure to add any other methods you use directly on dayjs. here

export default dayjs;
Sophie1142 commented 4 months ago

+1 on this request!

czq297297 commented 1 month ago

+1

EddyPBR commented 1 month ago

In the react application of a product I'm working on, my colleague @souzaneto25 and I launched the following:

// services/dayjs/index.ts

import dayjs from "dayjs";
import "dayjs/locale/pt-br";
import duration from "dayjs/plugin/duration";
import timezone from "dayjs/plugin/timezone";
import utc from "dayjs/plugin/utc";

// Plugins
dayjs.extend(utc);
dayjs.extend(timezone);
dayjs.extend(duration);

// Location
dayjs.locale("pt-br");

// Default
dayjs.tz.setDefault("America/Sao_Paulo");

export default dayjs;

We use this instance as the default throughout the application:

Then we replace import dayjs from "dayjs"; for this import dayjs from "~services/dayjs";

And it has worked well, I hope it helps.

t-monaco commented 3 weeks ago

In the react application of a product I'm working on, my colleague @souzaneto25 and I launched the following:

// services/dayjs/index.ts

import dayjs from "dayjs";
import "dayjs/locale/pt-br";
import duration from "dayjs/plugin/duration";
import timezone from "dayjs/plugin/timezone";
import utc from "dayjs/plugin/utc";

// Plugins
dayjs.extend(utc);
dayjs.extend(timezone);
dayjs.extend(duration);

// Location
dayjs.locale("pt-br");

// Default
dayjs.tz.setDefault("America/Sao_Paulo");

export default dayjs;

We use this instance as the default throughout the application:

Then we replace import dayjs from "dayjs"; for this import dayjs from "~services/dayjs";

And it has worked well, I hope it helps.

From my understanding, the .tz. setDefault(// desire timezone) does not change the dayjs() object so that should not work.

ruoqianfengshao commented 2 weeks ago

share my solution

  1. 
    import dayjs from "dayjs";
    import utc from "dayjs/plugin/utc";
    import timezone from "dayjs/plugin/timezone";
    import { extend, locale, unix, isDayjs, Dayjs } from "dayjs";

dayjs.extend(utc); dayjs.extend(timezone);

dayjs.tz.setDefault("America/Los_Angeles"); const newDayjs = (...args: any) => dayjs.tz(...args);

newDayjs.extend = extend; newDayjs.locale = locale; newDayjs.unix = unix; newDayjs.isDayjs = isDayjs; newDayjs.Dayjs = Dayjs; export { PluginFunc } from "dayjs";

export default newDayjs;

build to umd

2. 
because the parameters of dayjs.tz  are unequal of  parameters of  dayjs,so we give a patch for plugin timezone:
```js
d.tz = function (input, arg1, arg2) {
    // only use defaultTimezone
    var parseFormat = arg1; 
    var timezone = defaultTimezone;
    var previousOffset = tzOffset(+d(), timezone);
  1. and then,use alias to replace

    resolve: {
    alias: [
    { find: /^dayjs$/, replacement: 'your-dayjs-tz-package' },
    ]
    }

    Because replace happpen in runtime, so all dayjs type works well. It works with ant.design or other librarys so far.