D语言讨论 谁能把D语言的时间处理说明白?

· Created · Last modified by michael replied at · 1926 times read

@zty 你好,D 语言官方对时间模块进行了一些封装,也有对应的英文文章,比如:
https://dlang.org/articles/intro-to-datetime.html
https://dlang.org/phobos/core_time.html
https://dlang.org/phobos/std_datetime.html

当然也可以有第三方封装的时间库,像 java 7 时代就有 joda-time,我们也使用 D 语言封装了类似 joda-time 的日期时间库 hunt-time

hunt-time 的介绍

hunt-time is a time library and similar to Joda-time and Java.time api.

功能特性

  • LocalDate - date without time
  • LocalTime - time without date
  • Instant - an instantaneous point on the time-line
  • DateTime - full date and time with time-zone
  • DateTimeZone - a better time-zone
  • Duration and Period - amounts of time
  • Interval - the time between two instants
  • A comprehensive and flexible formatter-parser

LocalDate/LocalTime/LocalDateTime

LocalDate, a date API that represents a date without time; LocalTime, a time representation without a date; and LocalDateTime, which is a combination of the previous two. All of these types represent the local date and/or time for a region, but,they contain zero information about the zone in which it is represented, only a representation of the date and time in your current timezone.

First of all, these APIs support an easy instantiation:

LocalDate date = LocalDate.of(2018,2,13);
// Uses DateTimeformatter.ISO_LOCAL_DATE for which the format is: yyyy-MM-dd
LocalDate date = LocalDate.parse("2018-02-13");
LocalTime time = LocalTime.of(6,30);
// Uses DateTimeFormatter.ISO_LOCAL_TIME for which the format is: HH:mm[:ss[.SSSSSSSSS]]
// this means that both seconds and nanoseconds may optionally be present.
LocalTime time = LocalTime.parse("06:30");
LocalDateTime dateTime = LocalDateTime.of(2018,2,13,6,30);
// Uses DateTimeFormatter.ISO_LOCAL_DATE_TIME for which the format is the
// combination of the ISO date and time format, joined by 'T': yyyy-MM-dd'T'HH:mm[:ss[.SSSSSSSSS]]
LocalDateTime dateTime = LocalDateTime.parse("2018-02-13T06:30");

It’s easy to convert between them:

// LocalDate to LocalDateTime
LocalDateTime dateTime = LocalDate.parse("2018-02-13").atTime(LocalTime.parse("06:30"));
// LocalTime to LocalDateTime
LocalDateTime dateTime = LocalTime.parse("06:30").atDate(LocalDate.parse("2018-02-13"));
// LocalDateTime to LocalDate/LocalTime
LocalDate date = LocalDateTime.parse("2018-02-13T06:30").toLocalDate();
LocalTime time = LocalDateTime.parse("2018-02-13T06:30").toLocalTime();

Aside from that, it’s incredibly easy to perform operations on our date and time representations, using the plus and minus methods as well as some utility functions:

LocalDate date = LocalDate.parse("2018-02-13").plusDays(5);
LocalDate date = LocalDate.parse("2018-02-13").plus(3, ChronoUnit.MONTHS);
LocalTime time = LocalTime.parse("06:30").minusMinutes(30);
LocalTime time = LocalTime.parse("06:30").minus(500, ChronoUnit.MILLIS);
LocalDateTime dateTime = LocalDateTime.parse("2018-02-13T06:30").plus(Duration.ofHours(2));
// using TemporalAdjusters, which implements a few useful cases:
LocalDate date = LocalDate.parse("2018-02-13").with(TemporalAdjusters.lastDayOfMonth());

Difference in Time: Duration and Period

As you’ve noticed, in one of the above examples we’ve used a Duration object. Duration and Period are two representations of time between two dates, the former representing the difference of time in seconds and nanoseconds, the latter in days, months and years.

When should you use these? Period when you need to know the difference in time between two LocalDaterepresentations:

Period period = Period.between(LocalDate.parse("2018-01-18"), LocalDate.parse("2018-02-14"));

Duration when you’re looking for a difference between a representation that holds time information:

Duration duration = Duration.between(LocalDateTime.parse("2018-01-18T06:30"), LocalDateTime.parse("2018-02-14T22:58"));

When outputting Period or Duration using toString(), a special format will be used based on ISO-8601 standard. The pattern used for a Period is PnYnMnD, where n defines the number of years, months or days present within the period. This means that P1Y2M3D defines a period of 1 year, 2 months, and 3 days. The ‘P’ in the pattern is the period designator, which tells us that the following format represents a period. Using the pattern, we can also create a period based on a string using the parse() method.

// represents a period of 27 days
Period period = Period.parse("P27D");

When using Durations, we move away slightly from the ISO-8601 standard. The pattern defined by ISO-8601 is PnYnMnDTnHnMn.nS. This is basically the Period pattern, extended with a time representation. In the pattern, T is the time designator, so the part that follows defines a duration specified in hours, minutes and seconds.

Last but not least, we can also retrieve the various parts of a period or duration, by using the corresponding method on a type. However, it’s important to know that the various datetime types also support this through the use of ChronoUnit enumeration type. Let’s take a look at some examples:

// represents PT664H28M
Duration duration = Duration.between(LocalDateTime.parse("2018-01-18T06:30"), LocalDateTime.parse("2018-02-14T22:58"));
// returns 664
long hours = duration.toHours();
// returns 664
long hours = LocalDateTime.parse("2018-01-18T06:30").until(LocalDateTime.parse("2018-02-14T22:58"), ChronoUnit.HOURS);

Working With Zones and Offsets: ZondedDateTime and OffsetDateTime

Thus far, we’ve shown how the new date APIs have made a few things a little easier. What really makes a difference, however, is the ability to easily use date and time in a timezone context. Hunt.time provides us with ZonedDateTime and OffsetDateTime, the first one being a LocalDateTime with information for a specific Zone (e.g. Europe/Paris), the second one being a LocalDateTime with an offset. What’s the difference? OffsetDateTime uses a fixed time difference between UTC/Greenwich and the date that is specified, whilst ZonedDateTime specifies the zone in which the time is represented, and will take daylight saving time into account.

Converting to either of these types is very easy:

OffsetDateTime offsetDateTime = LocalDateTime.parse("2018-02-14T06:30").atOffset(ZoneOffset.ofHours(2));
// Uses DateTimeFormatter.ISO_OFFSET_DATE_TIME for which the default format is
// ISO_LOCAL_DATE_TIME followed by the offset ("+HH:mm:ss").
OffsetDateTime offsetDateTime = OffsetDateTime.parse("2018-02-14T06:30+06:00");
ZonedDateTime zonedDateTime = LocalDateTime.parse("2018-02-14T06:30").atZone(ZoneId.of("Europe/Paris"));
// Uses DateTimeFormatter.ISO_ZONED_DATE_TIME for which the default format is
// ISO_OFFSET_DATE_TIME followed by the the ZoneId in square brackets.
ZonedDateTime zonedDateTime = ZonedDateTime.parse("2018-02-14T06:30+08:00[Asia/Macau]");
// note that the offset does not matter in this case.
// The following example will also return an offset of +08:00
ZonedDateTime zonedDateTime = ZonedDateTime.parse("2018-02-14T06:30+06:00[Asia/Macau]");

When switching between them, you have to keep in mind that converting from a ZonedDateTime to OffsetDateTimewill take daylight saving time into account, while converting in the other direction, from OffsetDateTime to ZonedDateTime, means you will not have information about the region of the zone, nor will there be any rules applied for daylight saving time. That is because an offset does not define any time zone rules, nor is it bound to a specific region.

ZonedDateTime winter = LocalDateTime.parse("2018-01-14T06:30").atZone(ZoneId.of("Europe/Paris"));
ZonedDateTime summer = LocalDateTime.parse("2018-08-14T06:30").atZone(ZoneId.of("Europe/Paris"));
// offset will be +01:00
OffsetDateTime offsetDateTime = winter.toOffsetDateTime();
// offset will be +02:00
OffsetDateTime offsetDateTime = summer.toOffsetDateTime();
OffsetDateTime offsetDateTime = zonedDateTime.toOffsetDateTime();
OffsetDateTime offsetDateTime = LocalDateTime.parse("2018-02-14T06:30").atOffset(ZoneOffset.ofHours(5));
ZonedDateTime zonedDateTime = offsetDateTime.toZonedDateTime();

看了2.0的文档半天时间,我也理不清D是怎么处理时间的。Clock.currTime()得到什么样的数据?
文档中时间处理说的一大堆一大堆,我不无法理清!!
关于时间,我们开发人员最关心的是:
1。取得时间(系统时间)最好要精确到毫秒以上。
2,时间转换:与标准时间的转换,与字串的转换,与时,分,秒。。转换
3,时间隔。这里有+,-,

我看文档中,有一堆我们用不上的!

我现在试用D, 很多时候,我要试试D的运行效率,那就要开始时间,结束时间,从而得到精确的时间差。从昨天我看文档找方法。没有!网上搜索,没有!
这是不是逼我放弃???重拾C++!

我是初学,喜欢D的语境。我不喜欢go语言的书写,就是那个左括,变态!因为我搞编程20年,从年轻时就喜欢{}上下对齐。go是个好语言。真正的简单!并发只要加个go就行了。用管道监视各协程。也喜欢go中的结构体,可以继承,封装等。rust我也有接触,安全第一,写起来费力,比C++有过之而无不及,感觉没有自由度,连变量都给框死,那还要变量做什么?所以我从内心不喜欢rust.最后选择了D.写起来感觉与C++也没有太多的区别,头文件不用,用import,不错!我写了几看C#,java,这个喜欢。语法上并不比C++简单!
有人说D简单,那就瞎说!加了N多新东西,到现在,我还不知道那!号是什么道理呢,文档上没人说。那~我只知道连接字串,似乎还能连接其他数据型,但规则是什么,没看到说明!。。。。。那文档上一堆的nothrow, pure safe@, 你大爷,你怎么不在文档前而解释?所以的class,struct,你也不把字段,方法列出来再解释?你不看看人家文档怎么写的?
一句话,这文档是给作者自己看的吧!!!你大爷!怪不得没人用你!浪费时间和精力!

如果对C++熟的话,直接引用c库就行。

import core.stdc.time;

int main(){
    clock_t begin=clock();
    ...
    clock_t end=clock();
    writeln(end-begin);
}

如果需求是测试效率,很简单
linux的time 命令就可以做到,win10系统可以 wsl time xx.exe 这样

如果是程序内部测试某函数的性能也很简单,标准库直接提供了 benchmark 函数,不需要记录开始时间,结束时间,再做减法,下面的程序测试 Boyer-Moore 算法和普通线性查找算法的时间

import std.datetime.stopwatch;
import std.stdio;
import std.algorithm.searching;
import std.conv;

void main(string[] args)
{
    if (args.length != 3)
    {
        return writeln("usage: test needle cnt");
    }

    string haystack = "Sets up Boyer-Moore matching for use with find below. 
By default, elements are compared for equality.
BoyerMooreFinder allocates GC memory.";
    writeln("program:\n", args[0]);

    auto  bmFinder = boyerMooreFinder(args[1]);
    void testbm()
    {
        bmFinder.beFound(haystack);
    }

    void testfind()
    {
        haystack.find(args[1]);
    }

    int cnt = args[2].parse!int;
    /// 重点在此 !!! benchmark 函数的结果精确到纳秒
    auto result = benchmark!(testbm, testfind)(cnt);
    writef("bm:%s\nln:%s\n", result[0], result[1]);
    writeln(result[1] - result[0]);
}

也可以分别使用dmd和ldc 分别编译测试,区别还是挺大的
记得加 -O 参数编译
输出结果中的单位含义如下
"weeks", "days", "hours", "minutes", "seconds", "msecs" (毫秒), "usecs", (微秒), "hnsecs" (百纳秒), and "nsecs"(纳秒).

Login to reply