An implementation of the tz database for the time-rs Rust crate.

Related tags

Database time-tz
Overview

time-tz

An implementation of the tz database for the time-rs Rust crate.

This implementation is based off of chrono-tz (https://github.com/chronotope/chrono-tz) but uses time-rs instead of chrono. This is designed to replace use of chono dependency which is impacted by CVE-2020-26235 (localtime_r thread safety issue linked to std::env::set_var).

This is currently an experimental crate.

Features

  • Injects an assume_timezone member function to any PrimitiveDateTime.
  • Injects a to_timezone member function to any OffsetDateTime.
  • Provides a timezones::get_by_name function to get a timezone by name.
  • Supports finding the closest IANA match from a windows timezone name.
  • Supports obtaining system's current timezone (through the system feature).

Usage

use time::macros::datetime;
use time_tz::{PrimitiveDateTimeExt, OffsetDateTimeExt, timezones};

fn main()
{
    // ===========================================
    //  Create a new datetime in a given timezone
    // ===========================================
    
    // First we have to get the source timezone:
    let london = timezones::db::europe::LONDON;
    // The function returns None if the timezone doesn't exist.

    // Now we can create a primitive date time and call the extension function:
    let dt = datetime!(2016-10-8 17:0:0).assume_timezone(london);


    // ===========================
    //  Convert to a new timezone
    // ===========================

    // First we get the target timezone:
    let berlin = timezones::db::europe::BERLIN;

    // Now we can convert (again by calling an extension function):
    let converted = dt.to_timezone(berlin);

    // ... do something with converted
}
Comments
  • Support TZ environment variable

    Support TZ environment variable

    Perhaps this is out-of-scope, but I'm wondering if you have a plan to support the TZ (and maybe TZDIR) environment variables so that we can reproduce behavior of, for example,

    $ TZ="FOO+12:34" date "+%Z %z"
    FOO -1234
    $ TZ=":Cuba" date "+%Z %z"
    CST -0500
    
    opened by MiSawa 10
  • Parser for TZ

    Parser for TZ

    This provides an implementation of the TZ POSIX environment variable specification for timezone information.

    This exposes a new API function time_tz::parse_tz::parse(input: &str) which returns an owned type implementing the TimeZone trait.

    This currently needs a lot of testing to ensure the hacks works and the many "unwrap" also passes.

    Link to the spec: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap08.html#tag_08_03

    opened by Yuri6037 8
  • Incorrect handling of DST changeover for `PrimitiveDateTime`

    Incorrect handling of DST changeover for `PrimitiveDateTime`

    When using assume_timezone on a PrimitiveDateTime close to the forward DST changeover, I get an unexpected result for the offset in the end. In my opinion, time-tz does not yet handle the timezone correctly in this situation.

    The following test demonstrates the issue. I've also included a test for the backward changeover, but I think the behaviour there is acceptable.

    mod time_tz {
        use time::macros::datetime;
        use time_tz::timezones::db::CET;
        use time_tz::PrimitiveDateTimeExt as _;
    
        #[test]
        fn handles_forward_changeover() {
            assert_eq!(
                datetime!(2022-03-27 01:30).assume_timezone(CET),
                datetime!(2022-03-27 01:30 +01:00)
            );
        }
    
        #[test]
        fn handles_backward_changeover() {
            // During backward changeover, the hour between 02:00 and 03:00 occurs twice, so either answer is correct
            /* assert_eq!(
                datetime!(2022-10-30 02:30).assume_timezone(CET),
                datetime!(2022-10-30 02:30 +02:00)
            ); */
            assert_eq!(
                datetime!(2022-10-30 02:30).assume_timezone(CET),
                datetime!(2022-10-30 02:30 +01:00)
            );
        }
    }
    

    On 2022-03-27, the date of DST changeover in CET, 01:30 in CET is 00:30 in UTC, but 01:30 in UTC is 03:30 in CET due to DST changeover.

    My expectation of assume_timezone was that it behaves similar to assume_offset on PrimitiveDateTime, which considers the PrimitiveDateTime to be in the provided offset.

    The exhibited behaviour is correct when treating the PrimitiveDateTime as UTC, but I'd argue that this would not be very useful. If this is indeed the expected behaviour, the documentation should highlight this fact.

    I think the issue comes down to this line in assume_timezone:

    let offset = tz.get_offset_utc(&self.assume_utc());
    

    For completeness, I've included the behaviour of chrono-tz. Note that the second test panics, since the local time 02:30 is ambiguous during backward DST changeover in CET.

    mod chrono {
        use chrono::NaiveDate;
        use chrono::NaiveDateTime;
        use chrono::NaiveTime;
        use chrono::TimeZone;
        use chrono_tz::CET;
    
        #[test]
        fn handles_forward_changeover() {
            let local = CET
                .from_local_datetime(&NaiveDateTime::new(
                    NaiveDate::from_ymd(2022, 3, 27),
                    NaiveTime::from_hms(01, 30, 00),
                ))
                .unwrap();
    
            assert_eq!(local, CET.ymd(2022, 3, 27).and_hms(01, 30, 00));
        }
    
        #[test]
        #[should_panic]
        fn handles_backward_changeover() {
            let local = CET
                .from_local_datetime(&NaiveDateTime::new(
                    NaiveDate::from_ymd(2022, 10, 30),
                    NaiveTime::from_hms(02, 30, 00),
                ))
                .unwrap();
    
            assert_eq!(local, CET.ymd(2022, 10, 30).and_hms(02, 30, 00));
            assert_eq!(local, CET.ymd(2022, 10, 30).and_hms(02, 30, 00));
        }
    }
    
    opened by korrat 7
  • Fix assume timezone

    Fix assume timezone

    This PR finally fixes the behavior of assume_timezone and assume_timezone_utc. The assume_timezone function is now fixed to always assume the input PrimitiveDateTime is already in the target timezone. The assume_timezone_utc preserves the old behavior of assuming the input PrimitiveDateTime is actually in UTC.

    Fixes #5 Fixes #6

    opened by Yuri6037 3
  • Daylight Saving Time offsets are ignored

    Daylight Saving Time offsets are ignored

    DST values are not included in the values output by OffsetDateTimeExt::to_timezone and PrimitiveDateTimeExt::to_timezone. For example the code below:

    use time::macros::datetime; use time_tz::{timezones, TimeZone, OffsetDateTimeExt}; let london = timezones::db::europe::LONDON; let odt1 = datetime!(2021-01-01 12:0:0 UTC); println!("{:?}", london.get_offset_utc(&odt1)); println!("{}", odt1.to_timezone(london)); let odt2 = datetime!(2021-07-01 12:0:0 UTC); println!("{:?}", london.get_offset_utc(&odt2)); println!("{}", odt2.to_timezone(london));

    gives the following output:

    TzOffset { timespan: FixedTimespan { utc_offset: 0, dst_offset: 0, name: "GMT" } } 2021-01-01 12:00:00.0 +00:00:00 TzOffset { timespan: FixedTimespan { utc_offset: 0, dst_offset: 3600, name: "BST" } } 2021-07-01 12:00:00.0 +00:00:00

    Note that to_timezone gives an offset of zero for both dates even though the TzOffset instances are clearly different. The final line should have an offset of +1 hour.

    The source of the problem lies in the impl of Offset::to_utc for TzOffset in timezone_impl.rs. I believe the line:

    UtcOffset::from_whole_seconds(self.timespan.utc_offset as i32).unwrap()

    should read:

    UtcOffset::from_whole_seconds((self.timespan.utc_offset + self.timespan.dst_offset) as i32).unwrap()

    opened by idcollins 3
  • Fixed wrong handling of GetDynamicTimeZoneInformation

    Fixed wrong handling of GetDynamicTimeZoneInformation

    get_timezone() always returns Error::Undetermined unless summer time is used in the current locale.

    According to Documentation:

    Return value

    If the function succeeds, it returns one of the following values. | Return code/value | Description | |-|-| | TIME_ZONE_ID_UNKNOWN 0 | Daylight saving time is not used in the current time zone, because there are no transition dates. |

    Code 0 means success so you have to return the fetched timezone instead of Error::Undetermined.

    opened by picoHz 2
  • Impl std error

    Impl std error

    Thank you for the amazing crate! This PR consists of two commits: The first commit of the change implements std::error::Error for Error type so that it's easier for users to propagate the error returned by time-tz. The second commit is a result of cargo fmt, as I noticed there are some formatting issues like mixed tab-indentations and spaces-indentations.

    opened by MiSawa 2
  • Make assume_timezone UTC problem clear

    Make assume_timezone UTC problem clear

    Currently the behavior of assume_timezone is ambiguous: one might expect the given PrimitiveDateTime to be in UTC, another could expect the function to directly accept a PrimitiveDateTime which is in the destination timezone.

    I think the way forward is to deprecate the function assume_timezone as soon as possible, forwarding users to the replacement assume_timezone_utc which assumes the PrimitiveDateTime is already in UTC. Also necessary is to provide a clear documentation on how this new replacement actually works and make it clear it takes UTC!

    opened by Yuri6037 0
  • Handling assume_timezone when the provided PrimitiveDateTime is already in the target timezone

    Handling assume_timezone when the provided PrimitiveDateTime is already in the target timezone

    Currently the function assume_timezone is not intended to be used with non UTC PrimitiveDateTime and produces wrong values when close to DST changeover.

    We need a new API function to handle creating an OffsetDateTime from a PrimitiveDateTime and a Timezone assuming the given PrimitiveDateTime is already in the proper timezone.

    I think of introducing a new version of the library to handle the changeover in the current function named assume_timezone and introducing a new function named assume_timezone_utc to keep the current behavior of assuming the given PrimitiveDateTime is in UTC.

    Unresolved questions:

    • What's the best way to handle this?

    Additional doc:

    Testing code (thanks korrat) - to integrate as UT once implementation is done:

    mod time_tz {
        use time::macros::datetime;
        use time_tz::timezones::db::CET;
        use time_tz::PrimitiveDateTimeExt as _;
    
        #[test]
        fn handles_forward_changeover() {
            assert_eq!(
                datetime!(2022-03-27 01:30).assume_timezone(CET),
                datetime!(2022-03-27 01:30 +01:00)
            );
        }
    
        #[test]
        fn handles_backward_changeover() {
            // During backward changeover, the hour between 02:00 and 03:00 occurs twice, so either answer is correct
            /* assert_eq!(
                datetime!(2022-10-30 02:30).assume_timezone(CET),
                datetime!(2022-10-30 02:30 +02:00)
            ); */
            assert_eq!(
                datetime!(2022-10-30 02:30).assume_timezone(CET),
                datetime!(2022-10-30 02:30 +01:00)
            );
        }
    }
    
    opened by Yuri6037 0
  • Factorize automatic generation from IANA database

    Factorize automatic generation from IANA database

    Sorry for the not so short text below, but I thought some context was needed before exposing what I'd like to do.

    Context

    In the beginning of the year 2022, reacting to CVE-2020-26235, I migrated some of the repositories I was working on, from chrono to time, until I stumbled on some functionalities that needed to parse timezones. Then, I opened https://github.com/chronotope/chrono-tz/pull/93.

    That said, the PR I proposed is not really satisfying:

    1. with the name chrono_tz, you would expect to have chrono in it (so making chrono an optional feature sounds dumb)
    2. it looks like the extract from the IANA Database is a functionality by itself that might live in its own repository

    It's the second item that made me opened this issue (see below).

    What I'd like to do?

    I only found out today about your crate time-tz. I'm pretty happy about it because I'm pretty sure I'm gonna use it:smile:

    I quickly parsed the code from build.rs and it seems mostly similar to chrono-tz-build. I was actually already trying to extract that part into an independent crate (when working on https://github.com/chronotope/chrono-tz/pull/93). Would you be interested in such a modification? I'd be interested to actually do the work but I'd like to know first if the idea is sound and acceptable in your project?

    opened by woshilapin 3
Owner
null
The rust client for CeresDB. CeresDB is a high-performance, distributed, schema-less, cloud native time-series database that can handle both time-series and analytics workloads.

The rust client for CeresDB. CeresDB is a high-performance, distributed, schema-less, cloud native time-series database that can handle both time-series and analytics workloads.

null 12 Nov 18, 2022
The spatial message broker and database for real-time multiplayer experiences. Official Rust implementation.

WorldQL Server Rust implementation of WorldQL, the spatial message broker and database for real-time multiplayer experiences Setup Instructions ⚠️ Thi

null 214 Jan 2, 2023
Skybase is an extremely fast, secure and reliable real-time NoSQL database with automated snapshots and SSL

Skybase The next-generation NoSQL database What is Skybase? Skybase (or SkybaseDB/SDB) is an effort to provide the best of key/value stores, document

Skybase 1.4k Dec 29, 2022
Skytable is an extremely fast, secure and reliable real-time NoSQL database with automated snapshots and TLS

Skytable is an effort to provide the best of key/value stores, document stores and columnar databases, that is, simplicity, flexibility and queryability at scale. The name 'Skytable' exemplifies our vision to create a database that has limitless possibilities. Skytable was previously known as TerrabaseDB (and then Skybase) and is also nicknamed "STable", "Sky" and "SDB" by the community.

Skytable 1.4k Dec 29, 2022
tzdb — Time Zone Database

tzdb — Time Zone Database Static time zone information for tz-rs. This crate provides all time zones found in the Time Zone Database, currently in the

René Kijewski 33 Dec 15, 2022
A simple library for Firebase real-time database

Firerust A very simple library to implement the Firebase real-time database in your code with the best performance Instalation Add this to your Cargo.

Daniel Dimbarre 1 Apr 15, 2022
A high-performance, distributed, schema-less, cloud native time-series database

CeresDB is a high-performance, distributed, schema-less, cloud native time-series database that can handle both time-series and analytics workloads.

null 1.8k Dec 30, 2022
This crate allows you to send cypher queries to the REST endpoint of a neo4j database

rusted_cypher Rust crate for accessing the cypher endpoint of a neo4j server This crate allows you to send cypher queries to the REST endpoint of a ne

Livio Ribeiro 68 Dec 1, 2022
Scalable and fast data store optimised for time series data such as financial data, events, metrics for real time analysis

OnTimeDB Scalable and fast data store optimised for time series data such as financial data, events, metrics for real time analysis OnTimeDB is a time

Stuart 2 Apr 5, 2022
🧰 The Rust SQL Toolkit. An async, pure Rust SQL crate featuring compile-time checked queries without a DSL. Supports PostgreSQL, MySQL, SQLite, and MSSQL.

SQLx ?? The Rust SQL Toolkit Install | Usage | Docs Built with ❤️ by The LaunchBadge team SQLx is an async, pure Rust† SQL crate featuring compile-tim

launchbadge 7.6k Dec 31, 2022
A pure Rust database implementation using an append-only B-Tree file format.

nebari nebari - noun - the surface roots that flare out from the base of a bonsai tree Warning: This crate is early in development. The format of the

Khonsu Labs 194 Jan 3, 2023
A mini kv database demo that using simplified bitcask storage model with rust implementation

A mini kv database demo that using simplified bitcask storage model with rust implementation.

Wancheng Long 17 Nov 28, 2022
A user crud written in Rust, designed to connect to a MySQL database with full integration test coverage.

SQLX User CRUD Purpose This application demonstrates the how to implement a common design for CRUDs in, potentially, a system of microservices. The de

null 78 Nov 27, 2022
Rust version of the Haskell ERD tool. Translates a plain text description of a relational database schema to dot files representing an entity relation diagram.

erd-rs Rust CLI tool for creating entity-relationship diagrams from plain text markup. Based on erd (uses the same input format and output rendering).

Dave Challis 32 Jul 25, 2022
AgateDB is an embeddable, persistent and fast key-value (KV) database written in pure Rust

AgateDB is an embeddable, persistent and fast key-value (KV) database written in pure Rust. It is designed as an experimental engine for the TiKV project, and will bring aggressive optimizations for TiKV specifically.

TiKV Project 535 Jan 9, 2023
A programmable document database inspired by CouchDB written in Rust

PliantDB PliantDB aims to be a Rust-written, ACID-compliant, document-database inspired by CouchDB. While it is inspired by CouchDB, this project will

Khonsu Labs 718 Dec 31, 2022
A cross-platform terminal database tool written in Rust

gobang is currently in alpha A cross-platform terminal database tool written in Rust Features Cross-platform support (macOS, Windows, Linux) Mu

Takayuki Maeda 2.1k Jan 5, 2023
Pure rust embeddable key-value store database.

MHdb is a pure Rust database implementation, based on dbm. See crate documentation. Changelog v1.0.3 Update Cargo.toml v1.0.2 Update Cargo.toml v1.0.1

Magnus Hirth 7 Dec 10, 2022
influxdb provides an asynchronous Rust interface to an InfluxDB database.

influxdb influxdb provides an asynchronous Rust interface to an InfluxDB database. This crate supports insertion of strings already in the InfluxDB Li

null 9 Feb 16, 2021