为什么 LocalDateTime 实际上不是本地日期和时间?

Why isn't LocalDateTime actually a local date and time?

作为一名软件架构师,我真的很想使用 NodaTime,但是 'Local' 的概念让我们的代码非常难以使用(这让我和我的团队抓狂)! documentation,当提到 "local" 和 "global" 次时,说明如下:

The key difference is that people all around the world will agree on a global value simultaneously, whereas they may all see different local values for the same global value, due to time zones.

这句话是通过本地时间的定义来定义全球时间的意思。因此,在了解全球时间之前,我们必须先了解本地时间的含义。

Google(以及许多其他类似的词典)将“Local Time”定义为:

Time as reckoned in a particular region or time zone.

  • time at a particular place as measured from the sun's transit over the meridian at that place, defined as noon.

因此,当地时间是由 时区 定义(或绑定)的特定时间 - 知道了。现在我们完全理解了全球时间的含义;好的,下一句:

A local value has no associated time zone in Noda Time;

等等!什么...?! 文档刚刚通过使用普遍接受的本地时间定义定义了全球时间( 与时区相关联)现在他们决定完全否定它的意义,如果那是真的,那么全球时间现在意味着什么?恕我直言,绝对没有。

文档继续说明...

in particular it is not just "a date and time fixed to the local time of the computer running the code"

我对这个陈述有两个问题:

  1. 文档无法使用'local time'的通用定义来尝试来描述它不是什么。这就像在说:X is equal to (NOT X) is true.
  2. 既然使用电脑的日期和时间正是"Local Time"的定义,那我怎么称呼本地时间呢?

我认为我们使用的定义比 'Local' 更好,'Raw' 这个词怎么样?这意味着:

Being in or nearly in the natural state: not processed or purified.

嗯嗯....

A [raw] value has no associated time zone in Noda Time; in particular it is not just "a date and time fixed to the local time of the computer running the code"

现在这听起来更像是文档试图传达的定义。

或者,也许其他人可以想出比 'Raw' 更好的词;但关键是,请把'Local'的真正含义还给我们,因为'Local'在软件和生活中都有非常真实和非常有用的含义。

因此,我们能否将 Local[Date][Time] 类 重命名为 Raw[Date][Time] 并(可选)添加名为 Local[Date][Time] 的新 类 即 绑定到计算机的本地时区吗?


@Michal 和@J...-

我们遇到的问题是无法理解 'our' 本地的 LocalDateTime(因为它是无区域的)。我们在使用 LocalDateTime 时遇到的问题是它 zoneless。从本质上讲,LocalDateTime应该是,顾名思义,是ZonedDateTime的一种特殊类型。 (就像 UTC 在概念上(具体而言)是 ZonedDateTime 的一种特殊类型。因此,UTC 可以拥有自己的一组类型,例如:Utc[Date][Time];在给定正确的问题域的情况下,它可能非常很有用。因为 UtcDateTime 还没有 'taken',我们可以在不干扰 NodaTime 的情况下创建这样一个概念。)

回到我们的问题,例如:如果我有两个 ZonedDateTimes,一个来自纽约,另一个来自西雅图,我想从我当前的位置(比方说:达拉斯)研究这两个 ZonedDateTimes。我想写...

LocalDateTime fromNy = newYork.LocalDateTime; 
LocalDateTime fromWa = seattle.LocalDateTime;

但是,我得到了两个不相关的本地日期时间,它们彼此之间完全没有关系。事实上,如果不是因为 var 名称,我不知道哪个是哪个。

我想要的是两个已转换为 my 本地时区的 ZonedDateTimes,正如 属性 名称所暗示的那样。现在,这两个 LocalDateTime 值(其中 LocalDateTime 是 ZonedDateTime 的一种特殊类型)具有相关含义。我知道我可以通过执行以下操作获得接近我想要的东西;但它很乱,没有传达相同的语义并且丢失了时区信息。

DateTimeZone ct = BclDateTimeZone.ForSystemDefault();
LocalDateTime tx1 = newYork.WithZone(ct);
LocalDateTime tx2 = seattle.WithZone(ct);

我也希望能够像这样再次转换值:

ZonedDateTime wa = tx2.WithZone(seattleTimeZone);
ZonedDateTime nw = tx2.WithZone(nyTimeZone);

这还允许:

instant.InUtc();
instant.InZone(zone);
instant.InLocal();

因此能够将即时时间映射到 3 个最常见的时区; UTC、本地和其他。但我不能,因为 LocalDateTime 不是 ZonedDateTime 的特殊类型。

恕我直言,NodaTime 1.x 不错,但不够灵活(或流畅),无法在黄金时段使用。但好消息是,它离它并不远。希望在 2.0(或更早版本)中可以解决这些问题。

@Michal - 我喜欢你关于 Noda[Date][Time] 的想法,而不是 Raw[Date][Time]

您可能感到困惑的是:

LocalDateTime = 特定日历(例如公历)中的通用时间,但由于没有附加 TimeZone,您无法区分这发生在全球时间线上的确切时间点。想象这只是一个通用值。例如。 14:00。您不知道 14:00 的确切时间,因为您不知道这是什么时区。

ZonedDateTime = LocalDateTime 在特定时区(您可能想象的是 LocalDateTime)。

我可能同意你的看法,这有点误导。我更希望它被称为 NodaDateTimeZonedDateTime 被称为 LocalDateTime 因为这样看起来更合乎逻辑。

编辑 - 以下评论

就个人而言,我很少使用 LocalDateTime,如果您坚持使用 InstantZonedDateTime 之间,您可能会摆脱很多头痛。有一个非常好的类型之间转换的概览图:

取自:nodatime.org - User Guide - Converting Between Types

所以在你的情况下你想做的是从特定的ZoneDateTime转换成Instant,然后再回到你想要的ZonedDateTime(你的系统tz)

例如

var myTz = BclDateTimeZone.ForSystemDefault();

var fromNy = SystemClock.Instance.Now.InZone(DateTimeZoneProviders.Tzdb["America/New_York"]);
// fromNy = 2015-03-22T08:28:56 America/New_York (-04)

var fromLa = SystemClock.Instance.Now.InZone(DateTimeZoneProviders.Tzdb["America/Los_Angeles"]);
// fromLa = 2015-03-22T05:28:56 America/Los_Angeles (-07)

var fromNyInMyTz = fromNy.ToInstant().InZone(myTz);
// localFromNy = 2015-03-22T12:28:56 GMT Standard Time (+00)

var fromLaInMyTz = fromLa.ToInstant().InZone(myTz);
// localFromLa = 2015-03-22T12:28:56 GMT Standard Time (+00)

您还可以创建一个扩展方法:

public static class NodaExtensions
{
    public static ZonedDateTime InUtc(this ZonedDateTime dt)
    {
        return dt.ToInstant().InUtc();
    }
    public static ZonedDateTime InZone(this ZonedDateTime dt, DateTimeZone tz)
    {
        return dt.ToInstant().InZone(tz);
    }
    public static ZonedDateTime InLocal(this ZonedDateTime dt)
    {
        return dt.ToInstant().InZone(BclDateTimeZone.ForSystemDefault());
    }
}

允许:

var fromNyInUtc = fromNy.InUtc();
var fromLaInUtc = fromLa.InUtc();

var fromNyInZone = fromNy.InZone(myTz);
var fromLaInZone = fromLa.InZone(myTz);

var fromNyInLocal = fromNy.InLocal();
var fromLaInLocal = fromLa.InLocal();

这是您想要的吗?