objectbox / objectbox-dart

Flutter database for super-fast Dart object persistence
https://docs.objectbox.io/getting-started
Apache License 2.0
927 stars 115 forks source link

UTC DateTime are getting converted to Local DateTime #308

Open raphire08 opened 2 years ago

raphire08 commented 2 years ago

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

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

gcostaapps commented 2 years ago

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?

ebadta81 commented 2 years ago

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

greenrobot-team commented 2 years ago

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);
  }
ebadta81 commented 2 years ago

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?

greenrobot-team commented 2 years ago

@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?

ebadta81 commented 2 years ago

@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.

raphire08 commented 2 years ago

@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.

ebadta81 commented 2 years ago

@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.

greenrobot-team commented 2 years ago

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.

raphire08 commented 2 years ago

@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.

vaind commented 2 years ago

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;
mprync commented 1 year ago

That is the correct way to do it.

dev-thinks commented 1 year ago

Is this already available or a proposal ?

froccawork commented 2 months ago

This proposal is available?

greenrobot-team commented 2 months ago

This proposal is available?

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

froccawork commented 2 months ago

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

Bohne13 commented 1 month ago

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 commented 1 month ago

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.