Skip to content

Conversation

@liquidiert
Copy link

@liquidiert liquidiert commented Oct 29, 2022

  • implemented datetime property type

references #5

Korbinian Habereder added 2 commits October 29, 2022 15:00
  - implemented datetime property type
@liquidiert
Copy link
Author

@vaind would be nice if you could take a look

PropertyType.string: flatbuffers.number_types.UOffsetTFlags,
# PropertyType.date: flatbuffers.number_types.Int64Flags,
PropertyType.date: flatbuffers.number_types.Int64Flags,
PropertyType.dateNano: flatbuffers.number_types.Float64Flags,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Date nano also use 64 bit integers; there should not be any floats involved?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry thought for the extra resolution of nano seconds this would be necessary

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Internally (e.g. FlatBuffers wise) it's ints and the resolution is "perfect" for a limited time (a couple of 200+ years left iirc) - I do not know about Python though and how to treat nano precision there...

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm I would see it as a little hack.
When I have a timestamp in nanosecond resolution e.g. 1667401463110012130 I'd have to divide it by 1.000.000.000 before I can use it in .fromtimestamp(). But the division is not different to using a float value in the first place. It might be even better to use floats to preserve precision cause:

>>> 1667401463110012130 / 1000000000
1667401463.110012

results in a precision loss. What do you think @greenrobot ?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The flatbuffers representation should not store floating point for date nano to match the other platforms. (binary compatibility, also because of sync)

val = prop._py_type(table.Bytes[start:start+size])
elif prop._ob_type == OBXPropertyType_Date or prop._ob_type == OBXPropertyType_DateNano:
table_val = table.Get(prop._fb_type, o + table.Pos)
val = datetime.fromtimestamp(table_val) if table_val != 0 else 0 # default timestamp
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you would need to differentiate Date vs. DateNano here? E.g. a factor of 1000000?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If floats are used this happens automatically

val = getattr(object, prop._name)
if val == prop:
return prop._py_type() # default (empty) value for the given type
if isinstance(val, datetime): # handle datetimes first
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not very familiar with specifics here; maybe we can avoid isinstance here and go via property type? I am assuming that isinstance takes more CPU cycles as it is common for reflective calls for the languages I know, but I am not familiar with Python internals.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

changed to use hasttr; property type is ambiguous unfortunately if val is the property itself

# TODO property type DATE
date_created = Property(int, id=3, uid=1003)
date_finished = Property(int, id=4, uid=1004)
date_created = Property(datetime, type=PropertyType.dateNano, id=3, uid=1003)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cool, one TODO less! 👍

Btw, using it in the example is great, and a test would be even better (optionally only if you want...)

def now_ms() -> int:
seconds: float = datetime.datetime.utcnow().timestamp()
return round(seconds * 1000)
return datetime.utcnow()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is much more readable. Does that also have similar (millisecond) precision?

Btw, The docs say that datetime.now(timezone.utc) is preferred for some reason, but I did not dig deeper.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Docs say this because of:

Because naive datetime objects are treated by many datetime methods as local times, it is preferred to use aware datetimes to represent times in UTC. As such, the recommended way to create an object representing the current time in UTC is by calling datetime.now(timezone.utc).

Gonna change it 👍

@liquidiert
Copy link
Author

@greenrobot any news on this? :)

@ivahnenkoAnna
Copy link
Contributor

Hey @liquidiert, we have just released Date types: https://github.com/objectbox/objectbox-python/releases/tag/v0.5.0. Thanks for your contribution, it was helpful and is highly appreciated! Unfortunately, we weren't able to include your commits in the release, as significant changes were needed to allow using both datetime and int types. If you plan to contribute in the future, we'd be happy to collaborate early on.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants