objectbox-dart icon indicating copy to clipboard operation
objectbox-dart copied to clipboard

UTC DateTime are getting converted to Local DateTime

Open raphire08 opened this issue 3 years ago • 26 comments

Save any variable with @Property(type: PropertyType.date) annotation with value as DateTime.now().toUtc() Read the same variable DateTime comes back in local time zone and UTC flag is false

  • ObjectBox version: [e.g. 0.14.0] objectbox: ^1.2.0 objectbox_flutter_libs: ^1.2.0

  • Flutter/Dart SDK: [e.g. 2.0.0, or the output of dart --version or flutter --version] Flutter 2.2.3 • channel stable • https://github.com/flutter/flutter.git Framework • revision f4abaa0735 (9 weeks ago) • 2021-07-01 12:46:11 -0700 Engine • revision 241c87ad80 Tools • Dart 2.13.4

  • Null-safety enabled: [yes | no] yes

  • Reproducibility: [e.g. occurred once only | occasionally without visible pattern | always] always

  • Device/Emulator: [e.g. Galaxy S20] iPhone 8+ Simulator

Additionally, you can choose to provide more details, e.g. the output of:

Steps to reproduce

  1. Put any entity class having variable as date in UTC
  2. Read the same entity class
  3. DateTime comes back in local timezone

Expected behavior

Date time should be in UTC only

raphire08 avatar Sep 03 '21 11:09 raphire08

I'll start building an application that has many datetime fields. Should I store the milliseconds in utc and always do the conversion to datetime or can I trust that the utc flag will be fixed without changing any values in future releases?

gcostaapps avatar Sep 04 '21 03:09 gcostaapps

I can confirm this bug. I was just running into it, and found this issue...

ebadta81 avatar Sep 12 '21 12:09 ebadta81

DateTime is stored as milliseconds (Unix timestamp) without any time zone information. When reading an object a DateTime property is restored with DateTime.fromMillisecondsSinceEpoch. The reasoning behind this is that most code won't explicitly use UTC time, but use the device default. So when reading an object ObjectBox also restores using the default time zone.

Edit: one could add a converter (custom getter/setter) that uses DateTime.fromMillisecondsSinceEpoch(value, isUtc: true) instead.

Example for the above:

  @Transient()
  DateTime? utcDate;

  int? get dbUtcDate => utcDate?.millisecondsSinceEpoch;

  set dbUtcDate(int? value) {
    utcDate = value == null
        ? null
        : DateTime.fromMillisecondsSinceEpoch(value, isUtc: true);
  }

greenrobot-team avatar Sep 13 '21 06:09 greenrobot-team

The main problem is, that the server I communicate, needs datetime with time zone information. If I get the datetime fields from the db, I get non utc datetime even if I store it in utc form.

And there is the DateTime.toIso8601String() dart function, which would convert the DateTime with timezone, if it would be utc (isUtc = true).

So the question is: how can we store (and read) DateTime with timezone in objectbox?

ebadta81 avatar Sep 15 '21 03:09 ebadta81

@ebadta81 I'm confused. You say you want to store using time in UTC (so time without time zone). Why does the above suggestion using a getter/setter then not work for you?

greenrobot-team avatar Sep 21 '21 11:09 greenrobot-team

@ebadta81 I'm confused. You say you want to store using time in UTC (so time without time zone). Why does the above suggestion using a getter/setter then not work for you?

I use the dart json_serializable package, for automated json serialisation. This package use the DateTime.toIso8601String() dart function in the generated code.

I would like to use objectbox and json_serializable out of the box.

My server needs the datetime with timezone. I checked the toIso8601String() function, and it gives timezone string if the datetime is utc

if (isUtc) {
      return "$y-$m-${d}T$h:$min:$sec.$ms${us}Z";
    } else {
      return "$y-$m-${d}T$h:$min:$sec.$ms$us";
    }

You are right, I can use a getter/setter in my classes, but I have to define it for every DateTime field in every class, and it has some overhead.

in summary, I would like to produce datetime fields with timezone information in my json structure, and send it to the server.

ebadta81 avatar Sep 22 '21 12:09 ebadta81

@ebadta81

I had the exact same requiment

I am storing values as local date time only and before sending to the server, I am doing a loop over the list (after reading from the database) to convert the time to UTC. I thought this would be a better option than getter and setter. I may be wrong though.

raphire08 avatar Sep 22 '21 15:09 raphire08

@ebadta81

I had the exact same requiment

I am storing values as local date time only and before sending to the server, I am doing a loop over the list (after reading from the database) to convert the time to UTC. I thought this would be a better option than getter and setter. I may be wrong though.

Hehe, I do exactly the same, in my code. :)

But this is only a workaround for the objectbox design problem.

ebadta81 avatar Sep 22 '21 21:09 ebadta81

So we are thinking about changing the read back milliseconds value to be converted using DateTime.fromMillisecondsSinceEpoch(value, isUtc: true). So DateTime of a read Object would be in UTC.

This would make sense as a DateTime is stored by using DateTime.millisecondsSinceEpoch which obtains a "Unix epoch" timestamp, which is also UTC.

The problem is this does break existing code, no? E.g. to display the value in the UI with https://pub.dev/packages/intl it would then be necessary to call DateTime.toLocal() first to get the same time zone as before.

greenrobot-team avatar Oct 18 '21 06:10 greenrobot-team

@greenrobot-team Yes it will break the existing code, not only for display but also in case of query operations. But, I guess you can put it in migration note. So anybody switching to newer branch will also change their code.

raphire08 avatar Oct 19 '21 07:10 raphire08

Another option (non-breaking) would be to provide an annotation/option to switch to reading UTC time. For example like on the following fields:

@Property(type: PropertyType.date, isUtc: true)
int date;
@Property(isUtc: true)
DateTime date;

or

@UTC
DateTime date;

vaind avatar Dec 29 '21 09:12 vaind

That is the correct way to do it.

mprync avatar Aug 21 '22 17:08 mprync

Is this already available or a proposal ?

dev-thinks avatar Dec 14 '22 19:12 dev-thinks

This proposal is available?

froccawork avatar Feb 26 '24 16:02 froccawork

This proposal is available?

Not yet. We were asking for feedback on what is preferred.

greenrobot-team avatar Feb 27 '24 06:02 greenrobot-team

Maybe the best choice would be the @Property(isUtc: true) Thanks

froccawork avatar Feb 27 '24 08:02 froccawork

Maybe the best choice would be the @Property(isUtc: true) Thanks

I try to write a program with a lot of DateTime values and everything should be always in UTC.

So having some tool like @Property(isUtc: true) soon, would be awesome!

Bohne13 avatar Apr 11 '24 16:04 Bohne13

This proposal is available?

Not yet. We were asking for feedback on what is preferred.

@Property(type: PropertyType.date, isUtc: true)
DateTime date;

would be the most consistent solution compared to, how DateTime values are handled.

@Utc
DateTime date;

would be the shortest one.

with moder IDE's and autocomplete, I would prefer the most consistent solution to already existing code.

Bohne13 avatar Apr 11 '24 16:04 Bohne13