3 个版本 (破坏性更新)

0.2.0 2024年5月28日
0.1.0 2023年4月14日
0.0.0 2023年1月26日

#369国际化 (i18n)

Download history 80/week @ 2024-05-22 77/week @ 2024-05-29 12/week @ 2024-06-05 29/week @ 2024-06-12 48/week @ 2024-06-19 94/week @ 2024-06-26 207/week @ 2024-07-03 209/week @ 2024-07-10 161/week @ 2024-07-17 150/week @ 2024-07-24 159/week @ 2024-07-31 212/week @ 2024-08-07 156/week @ 2024-08-14

每月700 次下载
2 个包中使用 (通过 temporal_rs)

Unicode-3.0

115KB
2K SLoC

ixdtf crates.io

扩展日期时间字符串和持续时间解析的解析器。

互联网扩展日期/时间格式 (IXDTF) 由 RFC 9557 定义。RFC 9557 在 RFC3339 的时间戳规范和 ISO8601 的基础上,为日期/时间字符串提供可选的扩展语法。RFC 9557 还更新了 RFC3339 “在特定解释本地偏移量 Z”。

日期时间扩展示例

  • 2024-03-02T08:48:00-05:00[美洲/纽约]
  • 2024-03-02T08:48:00-05:00[-05:00]
  • 2024-03-02T08:48:00-05:00[u-ca=iso8601]

示例用法

use ixdtf::parsers::{
    records::{Sign, TimeZoneRecord},
    IxdtfParser,
};

let ixdtf_str = "2024-03-02T08:48:00-05:00[America/New_York]";

let result = IxdtfParser::new(ixdtf_str).parse().unwrap();

let date = result.date.unwrap();
let time = result.time.unwrap();
let offset = result.offset.unwrap();
let tz_annotation = result.tz.unwrap();

assert_eq!(date.year, 2024);
assert_eq!(date.month, 3);
assert_eq!(date.day, 2);
assert_eq!(time.hour, 8);
assert_eq!(time.minute, 48);
assert_eq!(offset.sign, Sign::Negative);
assert_eq!(offset.hour, 5);
assert_eq!(offset.minute, 0);
assert!(!tz_annotation.critical);
assert_eq!(tz_annotation.tz, TimeZoneRecord::Name("America/New_York"));

日期/时间字符串

RFC 9557 规定的扩展后缀是可选的,因此 IxdtfParser 也将解析任何由 RFC3339 描述的有效日期/时间字符串。

有效日期/时间字符串示例

  • 2024-03-02
  • +002024-03-02
  • 20240302
  • +0020240302
  • 2024-03-02T08:48:00
  • 2024-03-02T08:48:00

RFC 9557 扩展:深入了解

后缀扩展主要有两种类型:时区注解和键值注解。后缀也可以用 ! 作为前导标志字符标记为关键。

时区注解

时区注解可以是有效的 IANA 时区名称或数字偏移量。

有效时区注解
  • 2024-03-02T08:48:00-5:00[美洲/纽约]
  • 2024-03-02T08:48:00-5:00[-05:00]

键值注解

键值对注解是由等号 ('=') 分隔的任何键和值字符串。键值对可以包含任何信息。键可以是永久注册的、临时注册的或未知的;然而,只有永久键才会被 IxdtfParser 所处理。

如果提供了重复注册的键,则将返回第一个键,除非其中一个重复注解被标记为关键,在这种情况下,ixdtf(请参阅 无效注解 以获取更多信息)可能会抛出错误。

永久注册密钥
  • u-ca
有效的注释
  • (1) 2024-03-02T08:48:00-05:00[America/New_York][u-ca=iso8601]
  • (2) 2024-03-02T08:48:00-05:00[u-ca=iso8601][u-ca=japanese]
  • (3) 2024-03-02T08:48:00-05:00[u-ca=iso8601][!u-ca=iso8601]
  • (4) 2024-03-02T08:48:00-05:00[u-ca=iso8601][answer-to-universe=fortytwo]
示例 1

这是一个包含时区和日历注释的基本注释字符串。

示例 2

此示例包含重复且不同的日历注释,但两个日历均未标记为关键,因此返回第一个日历,忽略第二个日历。

示例 3

此示例是重复且相同的日历注释,其中有一个注释标记为关键。由于注释值相同,使用关键标志可能导致错误的情况不会产生歧义。因此,返回第一个注释,忽略第二个注释(参见 具有应用程序定义行为的注释)。

示例 4

此示例包含一个未知注释。注释未标记为关键,因此忽略该值(参见 实现注释处理程序)。

无效注释

以下 ixdtf 字符串包含无效注释,将引发错误(注意:这些与具有应用程序定义行为的潜在无效注释不同)。

  • (1) 2024-03-02T08:48:00-05:00[u-ca=iso8601][America/New_York]
  • (2) 2024-03-02T08:48:00-05:00[u-ca=iso8601][!u-ca=japanese]
  • (3) 2024-03-02T08:48:00-05:00[u-ca=iso8601][!answer-to-universe=fortytwo]
示例 1

此示例展示了时间区域注解当前与键值不正确排序的情况。当解析此无效注解时,ixdtf将尝试将时间区域注解解析为键值注解。

use ixdtf::{parsers::IxdtfParser, ParserError};

let example_one =
    "2024-03-02T08:48:00-05:00[u-ca=iso8601][America/New_York]";

let mut ixdtf = IxdtfParser::new(example_one);

let result = ixdtf.parse();

assert_eq!(result, Err(ParserError::AnnotationKeyLeadingChar));
示例 2

此示例展示了重复注册的键;然而,在这种情况下,其中一个注册的键被标记为关键,这会导致错误,因为ixdtf字符串必须被视为错误。

use ixdtf::{parsers::IxdtfParser, ParserError};

let example_one = "2024-03-02T08:48:00-05:00[u-ca=iso8601][!u-ca=japanese]";

let result = IxdtfParser::new(example_one).parse();

assert_eq!(result, Err(ParserError::CriticalDuplicateCalendar));
示例 3

此示例展示了被标记为关键的未知键。ixdtf将返回错误,因为未知标志被标记为关键。

use ixdtf::{parsers::IxdtfParser, ParserError};

let example_one =
    "2024-03-02T08:48:00-05:00[u-ca=iso8601][!answer-to-universe=fortytwo]";

let result = IxdtfParser::new(example_one).parse();

assert_eq!(result, Err(ParserError::UnrecognizedCritical));
具有应用程序定义行为的注解

以下选项可能被视为有效或无效,具体取决于应用程序定义的行为。如果需要用户定义的行为,ixdtf crate将应用最不限制的解释逻辑,并为用户提供可选的回调来定义更严格的行为。

  • (1) 2024-03-02T08:48:00-05:00[u-ca=japanese][!u-ca=japanese]
  • (2) 2024-03-02T08:48:00+01:00[America/New_York]
示例 1

本示例展示了一个关键重复日历,其中注释值相同。RFC 9557对于是否应因不一致性而拒绝它存在歧义。ixdtf将这些值视为一致,因此是可接受的。然而,应用程序可能希望将这个重复的关键日历值视为不一致(见实现注释处理程序)。

示例 2

本示例展示了一个由偏移量和时区注释不匹配引起的模糊时区。处理偏移量和注释之间的歧义取决于用户。

use ixdtf::parsers::{IxdtfParser, records::TimeZoneRecord};

let example_one = "2024-03-02T08:48:00+01:00[!America/New_York]";

let mut ixdtf = IxdtfParser::new(example_one);

let result = ixdtf.parse().unwrap();

let tz_annotation = result.tz.unwrap();
let offset = result.offset.unwrap();

// The time zone annotation and offset conflict with each other, and must therefore be
// resolved by the user.
assert!(tz_annotation.critical);
assert_eq!(tz_annotation.tz, TimeZoneRecord::Name("America/New_York"));
assert_eq!(offset.hour, 1);
实现注释处理程序

如前所述,有时应用程序可能需要实现应用程序定义的行为来实现用户定义的功能。在这种情况下,ixdtf提供了一个*_with_annotation_handler方法,允许用户提供回调。

处理程序被定义为handler: impl FnMut(Annotation<'a>) -> Option<Annotation<'a>>,其中ixdtf将注释提供给用户。在调用此回调之前,会调用此回调,并且仅在将注释返回给ixdtf时才会发生。

如果用户希望忽略任何ixdtf的错误,则可以返回None,这将导致对该注释执行无操作。

除非用户的程序有特定的原因要绕过注释上的操作,例如自定义未知键处理或基于它的重要标志覆盖日历,否则建议返回注释值。

处理程序示例

用户可能希望在注释集中实现一个自定义键。这可以通过自定义处理程序来完成。

use ixdtf::parsers::IxdtfParser;

let example_with_custom_key = "2024-03-02T08:48:00-05:00[u-ca=iso8601][!answer-to-universe=fortytwo]";

let mut answer = None;

let _ = IxdtfParser::new(example_with_custom_key).parse_with_annotation_handler(|annotation| {
    if annotation.key == "answer-to-universe" {
        answer.get_or_insert(annotation);
        // Found our value! We don't need `ixdtf` to handle this annotation.
        return None
    }
    // The annotation is not our custom annotation, so we return
    // the value back for regular logic.
    Some(annotation)
}).unwrap();

let answer = answer.unwrap();

assert!(answer.critical);
assert_eq!(answer.value, "fortytwo");

值得注意的是,在上面的示例中,找到的注释是一个标记为关键的重要未知键。RFC 9557和ixdtf认为未知的关键键是无效的。但是,处理程序允许用户定义自己的任何已知键,因此也可以处理关键性逻辑。

其他语法资源

有关日期和时间字符串语法的其他资源可以在RFC3339Temporal提案中找到。

其他功能

ixdtf crate还实现了ISO8601持续时间解析器(IsoDurationParser),该解析器位于duration功能标志下。与IxdtfParser的API相同,但它解析日期/时间字符串上的持续时间字符串。

更多信息

有关开发、作者、贡献等更多信息,请访问ICU4X 主页

依赖关系

~275–730KB
~17K SLoC