Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Add Jiff support#1164

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Merged
sfackler merged 8 commits intorust-postgres:masterfromallan2:jiff
Aug 18, 2024
Merged

Add Jiff support#1164

sfackler merged 8 commits intorust-postgres:masterfromallan2:jiff
Aug 18, 2024

Conversation

allan2
Copy link
Contributor

This PR adds support for version 0.1 ofJiff.

Jiff is inspired byTemporal, aTC39 proposal to improve datetime handling in JavaScript.

The implementation injiff_01.rs is based onchrono_04.rs. When usingFromSql andToSql,Zoned sets the timezone to UTC.
Jiff does not support leap seconds, which is nice because Postgres doesn't either.

Closes#1163

@allan2allan2 changed the titleAdd jiff supportAdd Jiff supportJul 22, 2024
fn from_sql(type_: &Type, raw: &[u8]) -> Result<JiffTimestamp, Box<dyn Error + Sync + Send>> {
Ok(DateTime::from_sql(type_, raw)?
.to_zoned(TimeZone::UTC)?
.timestamp())

Choose a reason for hiding this comment

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

I'm not intricately familiar with how PostgreSQL represents time, but it seems like you can avoid going through aDateTime here and just compute aJiffTimestamp directly.

allan2 reacted with thumbs up emoji
Copy link
ContributorAuthor

Choose a reason for hiding this comment

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

Addressed inf00d208


impl<'a> FromSql<'a> for Zoned {
fn from_sql(type_: &Type, raw: &[u8]) -> Result<Zoned, Box<dyn Error + Sync + Send>> {
Ok(JiffTimestamp::from_sql(type_, raw)?.to_zoned(TimeZone::UTC))

Choose a reason for hiding this comment

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

Is it correct to assume UTC here? There is no time zone information in PostgreSQL?

I wonder if it makes sense to leave out the impl forZoned and instead require that callers just use ajiff::Timestamp and do their own conversions toZoned as needed.

Copy link
ContributorAuthor

Choose a reason for hiding this comment

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

UTC is correct. From thePostgres docs:

Fortimestamp with time zone, the internally stored value is always in UTC... An input value that has an explicit time zone specified is converted to UTC using the appropriate offset for that time zone. If no time zone is stated in the input string, then it is assumed to be in the time zone indicated by the system'sTimeZone parameter, and is converted to UTC using the offset for the timezone zone.

Consumers will usually reach forTimestamp, butZoned beingToSql andFromSql can occasionally be convenient. I am in favour of including them. It would also matchchrono::DateTime<FixedOffset> andtime::OffsetDateTime having them.

Choose a reason for hiding this comment

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

I'm skeptical that aZoned implementation makes sense here personally. Think of aZoned as "an assertion that a particular datetime is in a specific geographic region." Just because youcan pick some kind of default here doesn't mean you should. And the civil datetime types are also somewhat questionable given that you're freely going to and from instants in time and back to inexact time. That also seems wrong.

I understand you're starting from a position of "this is how the Chrono integration works," but Chrono'sDateTime<FixedOffset> and time'sOffsetDateTime are much closer to Jiff'sTimestamp than Jiff'sZoned. The closest analog Chrono has to a JiffZoned isDateTime<chrono_tz::Tz>.

The only trait implementation I feel 100% confident about here is forjiff::Timestamp.

Copy link
ContributorAuthor

Choose a reason for hiding this comment

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

I have always felt weird about how Postgres handles time zones and how thetimestamp with time zone type does not in fact contain the time zone information. Keeping the actual geographic region requires an additional column. What you wrote aboutZoned resonates with me when it comes to correctness. I agree thatjiff::Timestamp matches up withtimestamptz andZoned does not match with any current Postgres datetime type. I was concerned about conforming to Postgres and this crate's implementation details but I agree with you now on omitting impl forZoned.

I am not sure I agree with your civil type concerns though. I feel like the Postgres types match up quite nicely for these inexact expressions of time

(Postgres also has atimetz. Can we express that in Jiff?)

Choose a reason for hiding this comment

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

REZoned: okay, great. Thank you.

I am not sure I agree with your civil type concerns though. I feel like the Postgres types match up quite nicely for these inexact expressions of time

I'm going based on the code in this PR. What I see is that a PostgreSQL timestamp (which is exact time) is being convert to and from a Jiffcivil::DateTime, which is inexact time. Going from inexact time to exact timeshould require some assertion of time zone. Indeed, if you add a time zone to acivil::DateTime, then you get aZoned. The same reason that aZoned impl is inappropriate applies here.

AIUI, PostgreSQL does haveDate andTime types, and those are inexact times, just like Jiff'scivil::Date andcivil::Time types.

Now that I look closer at this patch, I see that aDateTime is being constructed from a timestamp, whileDate andTime are being constructed from PostgreSQLdate andtime types. The fact that these are different is 100% certainly wrong. I don't think PostgreSQL has adatetime type (something that combinesdate andtime), so probably thejiff::civil::DateTime implementation should be removed.

Basically, any time you move between exact and inexact time, you should have some kind of time zone assertion involved. Andusually, "just use UTC" is not the right thing to do.

(Postgres also has a timetz. Can we express that in Jiff?)

Noooooooooo. See:https://wiki.postgresql.org/wiki/Don%27t_Do_This#Don.27t_use_timetz

Copy link
ContributorAuthor

Choose a reason for hiding this comment

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

timestamp in Postgres isinexact, being a combination ofdate andtime without time zone. It can be used to record the general idea of the 2025 New Year's Countdown, taking place on Dec 31, 2024 at 11:59pm, without regard for the geographic location.

timestamptz is exact., asserting the time zone (albeit in UTC only).

Copy link

@BurntSushiBurntSushiJul 23, 2024
edited
Loading

Choose a reason for hiding this comment

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

timestamp in Postgres is inexact, being a combination of date and time without time zone.

Whoa. OK. Let me backup and read their docs more carefully... Because if atimestamp is just inexact time andtimestamptz is just inexact time with a time zone, then that doesnot make atimestamptz exact. It could be ambiguous. Butaccording to this, yes, PostgreSQL is saying that it is exact. So maybe they are doing disambiguation on insert or something. And also, this seems to indeed agree that just atimestamp is actually inexact time:

timestamp (also known as timestamp without time zone) doesn't do any of that, it just stores a date and time you give it. You can think of it being a picture of a calendar and a clock rather than a point in time. Without additional information - the timezone - you don't know what time it records.

Wild.

I had assumed thattimestamp was, well, just a Unix timestamp. Which is always in UTC. Andtimestamptz stored some extra bit of information like an offset. OK, so I think this is the mapping then:

  • date ->jiff::civil::Date
  • time ->jiff::civil::Time
  • timestamp ->jiff::civil::DateTime
  • timestamptz ->jiff::Timestamp

I think where I got confused is that in this patch, thetimestamp -> jiff::civil::DateTime is implemented by using what appears to be a representation for exact time (number of seconds since an epoch). But I guess that's just a representational thing.

And yes, it looks like the above mapping lines up with what you have in this PR. OK, sorry for the noise!

Copy link
ContributorAuthor

Choose a reason for hiding this comment

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

I had assumed thattimestamp was, well, just a Unix timestamp. Which is always in UTC. Andtimestamptz stored some extra bit of information like an offset. OK, so I think this is the mapping then:

  • date ->jiff::civil::Date
  • time ->jiff::civil::Time
  • timestamp ->jiff::civil::DateTime
  • timestamptz ->jiff::Timestamp

I think where I got confused is that in this patch, thetimestamp -> jiff::civil::DateTime is implemented by using what appears to be a representation for exact time (number of seconds since an epoch). But I guess that's just a representational thing.

It's certainly confusing.

timestamp andtimestamptz both internally store microseconds since Y2K midnight UTC. The difference is thattimestamptz converts the input to UTC before storing the number of microseconds. It bakes in the offset so we get the correct exact time, but the actual source time zone/offset is discarded.

For the record,DateTime andTimestamp are much better names thantimestamp andtimestamptz to describe what they really are.

And yes, it looks like the above mapping lines up with what you have in this PR. OK, sorry for the noise!

Comments were much appreciated :) At least we're only dealing with Terran time.

BurntSushi reacted with heart emoji
The impl now directly computes `Timestamp` rather than going through`DateTime` and `Zoned`.
`Timestamp` already has impl and is semantically accurate for mapping to `timestamptz`, unlike `Zoned`.End users can do their own conversions from `Timestamp` to `Zoned` if desired.
@sfackler
Copy link
Collaborator

Can you also add some tests? Here are chrono's for reference:https://github.com/sfackler/rust-postgres/blob/master/tokio-postgres/tests/test/types/chrono_04.rs

This sets the smallest unit to microseconds when calculating time deltas.Previously, the number of microseconds was expressed improperly becausethe rounding was not set.
This adds tests in the same fashion as the existing ones for `chrono`and `time`.Overflow is now handled using fallible operations.For example, `Span:microseconds` is replaced with `Span::try_microseconds`.Postgres infinity values are workiing as expected.All tests are passing.
The implementation was previously removed as per jiff author comment.
@allan2
Copy link
ContributorAuthor

This PR is complete and ready for review. All tests are passing.

One minor note:

In the tests, I use jiff'sFromStr implementations to parse strings into date types.[1]

let s ="'1970-01-01 00:00:00.010000000Z'";let ts:Timestamp = s.trim_matches('\'').parse().unwrap();// I did thislet ts:Timestamp =Timestamp::strptime("'%Y-%m-%d %H:%M:%S.%f %#z'", s);// I could do this if you prefer

Special thanks to@cmarkh who openedallan2/rust-postgres#1, which I unfortunately missed.

@BurntSushi
Copy link

The FromStr impl should be used if possible IMO. It's more flexible (it permits aT separator between the date and time) and probably 2x faster since it's a dedicated parser.

@sfackler
Copy link
Collaborator

Thanks!

Sign up for freeto join this conversation on GitHub. Already have an account?Sign in to comment
Reviewers
1 more reviewer

@BurntSushiBurntSushiBurntSushi left review comments

Reviewers whose approvals may not affect merge requirements
Assignees
No one assigned
Labels
None yet
Projects
None yet
Milestone
No milestone
Development

Successfully merging this pull request may close these issues.

Support for jiff datetime types
3 participants
@allan2@sfackler@BurntSushi

[8]ページ先頭

©2009-2025 Movatter.jp