简体   繁体   English

Momentjs calendar()等同于Java

[英]Momentjs calendar() equivalent for Java

Momentjs has the calendar() function to pretty print timespans like below. Momentjs具有calendar()函数,可以实现如下所示的打印时间跨度。

For example: 例如:

"Last Monday at 1:14 PM" “上周一的1:14 PM”

"09/21/2017" (if the date is a while ago) “ 09/21/2017”(如果日期是前一阵子)

Is there an equivalent function in Java (Joda-Time if possible)? Java中是否有等效的功能(如果可能,可以使用Joda-Time)?

moment().subtract(10, 'days').calendar(); // 09/21/2017
moment().subtract(6, 'days').calendar();  // Last Monday at 1:14 PM
moment().subtract(3, 'days').calendar();  // Last Thursday at 1:14 PM
moment().subtract(1, 'days').calendar();  // Yesterday at 1:14 PM
moment().calendar();                      // Today at 1:14 PM
moment().add(1, 'days').calendar();       // Tomorrow at 1:14 PM
moment().add(3, 'days').calendar();       // Wednesday at 1:14 PM
moment().add(10, 'days').calendar();      // 10/11/2017

java.time java.time

Modern approach uses the industry-leading java.time classes. 现代方法使用行业领先的java.time类。

ZoneId z = ZoneId.now( “America/Montreal”  ) ;
LocalDate today = LocalDate.now( z ) ;

Use the plus and minus methods to do math. 使用加号和减号方法进行数学运算。

LocalDate tomorrow = today.plusDays( 1 ) ;

Search Stack Overflow. 搜索堆栈溢出。 Nearly every basic date-time Question has already been asked an answered. 几乎每个基本的日期时间问题都已经被要求回答。

Strings 字符串

The java.time classes do not generate strings such as “tomorrow” and “Last Monday”. java.time类不会生成诸如“明天”和“上周一”之类的字符串。 So no direct equivalent of your referenced library. 因此,没有直接等同于您引用的库的信息。 You will have to do the peasant work yourself. 您将不得不自己做农民工作。

Search for the DateTimeFormatter class, and the DateTimeFormatterBuilder class. 搜索DateTimeFormatter类和DateTimeFormatterBuilder类。

Also, the DayOfWeek enum and its auto-localizing getDisplayName method may be useful. 同样, DayOfWeek枚举及其自动本地化的getDisplayName方法可能很有用。

prettytime prettytime

The prettytime library may help you, though I've not used it. 尽管我没有使用过prettytime库,但它可能会对您有所帮助。

Joda-Time 乔达时间

The Joda-Time project is in maintenance mode. Joda-Time项目处于维护模式。 The team advises migration to the java.time classes. 该团队建议迁移到java.time类。


About java.time 关于java.time

The java.time framework is built into Java 8 and later. java.time框架内置于Java 8及更高版本中。 These classes supplant the troublesome old legacy date-time classes such as java.util.Date , Calendar , & SimpleDateFormat . 这些类取代了麻烦的旧的旧式日期时间类,例如java.util.DateCalendarSimpleDateFormat

The Joda-Time project, now in maintenance mode , advises migration to the java.time classes. 现在处于维护模式Joda-Time项目建议迁移到java.time类。

To learn more, see the Oracle Tutorial . 要了解更多信息,请参见Oracle教程 And search Stack Overflow for many examples and explanations. 并在Stack Overflow中搜索许多示例和说明。 Specification is JSR 310 . 规格为JSR 310

Where to obtain the java.time classes? 在哪里获取java.time类?

The ThreeTen-Extra project extends java.time with additional classes. ThreeTen-Extra项目使用其他类扩展了java.time。 This project is a proving ground for possible future additions to java.time. 该项目为将来可能在java.time中添加内容提供了一个试验场。 You may find some useful classes here such as Interval , YearWeek , YearQuarter , and more . 您可以在这里找到一些有用的类,比如IntervalYearWeekYearQuarter ,和更多

There's no built-in function for that in Java, but it's not so hard to do it with the existing API's. Java中没有内置函数,但是使用现有的API并不是很难。 First you need to get the difference from today (in days), and choose the proper string based on moment.js rules : 首先,您需要获得与今天(以天为单位)的差额,然后根据moment.js规则选择适当的字符串:

Last week         Last Monday at 2:30 AM
The day before    Yesterday at 2:30 AM
The same day      Today at 2:30 AM
The next day      Tomorrow at 2:30 AM
The next week     Sunday at 2:30 AM
Everything else   7/10/2011

In Joda-Time, you can use the org.joda.time.Days class to get the difference in days. 在Joda-Time中,可以使用org.joda.time.Days类来获取天数差异。 One detail is that I'm considering just the date (day/month/year) and ignoring the time (hour/minute/second) to get the difference (but you can adjust it to your needs). 一个细节是,我只考虑日期(日/月/年),而忽略了时间(小时/分钟/秒)来获得差异(但您可以根据需要进行调整)。 The method will be like this: 该方法将是这样的:

public String calendar(DateTime dt) {
    StringBuilder sb = new StringBuilder();

    // check difference in days from today, considering just the date (ignoring the hours)
    int days = Days.daysBetween(new LocalDate(), dt.toLocalDate()).getDays();
    if (days == 0) { // today
        sb.append("Today ");
    } else if (days == 1) { // tomorrow
        sb.append("Tomorrow ");
    } else if (days == -1) { // yesterday
        sb.append("Yesterday ");
    } else if (days > 0 && days < 7) { // next week
        sb.append(dt.dayOfWeek().getAsText(Locale.ENGLISH)).append(" ");
    } else if (days < 0 && days > -7) { // last week
        sb.append("Last ").append(dt.dayOfWeek().getAsText(Locale.ENGLISH)).append(" ");
    }

    if (Math.abs(days) < 7) { // difference is less than a week, append current time
        sb.append("at ").append(dt.toString("h:mm a", Locale.ENGLISH));
    } else { // more than a week of difference
        sb.append(dt.toString("M/d/yyyy"));
    }

    return sb.toString();
}

I'm using a org.joda.time.LocalDate to get the difference, so the time will be ignored (if you use a DateTime instead, the difference is only 1 day if it has passed more than 24 hours, so change the code according to what you need). 我正在使用org.joda.time.LocalDate来获取时差,因此时间将被忽略(如果您使用DateTime ,则经过24小时以上的时差仅为1天,因此请更改代码根据您的需要)。

I also used Math.abs(days) < 7 to consider if the difference is more than a week, but I'm not sure if moment.js considers <= 7 . 我还使用Math.abs(days) < 7来考虑差异是否超过一周,但是我不知道moment.js认为<= 7

Anyway, some examples of usage: 无论如何,一些用法示例:

DateTime now = new DateTime();
System.out.println(calendar(now.minusDays(10))); // 9/22/2017
System.out.println(calendar(now.minusDays(6))); // Last Tuesday at 9:34 AM
System.out.println(calendar(now.minusDays(3))); // Last Friday at 9:34 AM
System.out.println(calendar(now.minusDays(1))); // Yesterday at 9:34 AM
System.out.println(calendar(now)); // Today at 9:34 AM
System.out.println(calendar(now.plusDays(1))); // Tomorrow at 9:34 AM
System.out.println(calendar(now.plusDays(3))); // Thursday at 9:34 AM
System.out.println(calendar(now.plusDays(10))); // 10/12/2017

The output is (considering that today is October 2 nd 2017, and I ran the code at 9:34 AM in my local time): 输出(考虑到今天是10月2日2017年第二 ,我跑的代码在我的本地时间上午09点34分):

9/22/2017 2017年9月22日
Last Tuesday at 9:34 AM 上星期二上午9:34
Last Friday at 9:34 AM 上周五上午9:34
Yesterday at 9:34 AM 昨天上午9:34
Today at 9:34 AM 今天上午9:34
Tomorrow at 9:34 AM 明天上午9:34
Thursday at 9:34 AM 星期四上午9:34
10/12/2017 2017年10月12日

You can also modify the method to take a reference date to compare with (instead of using a hardcoded new LocalDate() inside the method). 您还可以修改该方法以获取一个参考日期进行比较(而不是在方法内部使用硬编码的new LocalDate() )。


Java new Date/Time API Java新的日期/时间API

Joda-Time is in maintainance mode and is being replaced by the new APIs, so I don't recommend start a new project with it. Joda-Time处于维护模式,并且已被新的API取代,因此,我不建议使用它来启动新项目。 Even in joda's website it says: "Note that Joda-Time is considered to be a largely “finished” project. No major enhancements are planned. If using Java SE 8, please migrate to java.time (JSR-310)." 即使在joda的网站上,它也说: “请注意,Joda-Time被认为是一个很大的“完成”项目。没有计划进行重大增强。如果使用Java SE 8,请迁移到java.time(JSR-310)。” .

If you're using Java 8 , consider using the new java.time API . 如果您使用的是Java 8 ,请考虑使用新的java.time API It's easier, less bugged and less error-prone than the old APIs . 与旧的API相比 ,它更容易, 更不会出错且更不会出错

If you're using Java 6 or 7 , you can use the ThreeTen Backport , a great backport for Java 8's new date/time classes. 如果您使用的是Java 6或7 ,则可以使用ThreeTen Backport ,它是Java 8的新日期/时间类的绝佳反向端口 And for Android , you'll also need the ThreeTenABP (more on how to use it here ). 对于Android ,您还需要ThreeTenABP (更多有关如何在此处使用它的信息 )。

The code below works for both. 下面的代码对两者都适用。 The only difference is the package names (in Java 8 is java.time and in ThreeTen Backport (or Android's ThreeTenABP) is org.threeten.bp ), but the classes and methods names are the same. 唯一的区别是包名称(在Java 8中为java.time ,在ThreeTen Backport(或Android的ThreeTenABP)中为org.threeten.bp ),但是类和方法相同。

This API is very similar to Joda-Time, so the code has minor differences: 该API与Joda-Time非常相似,因此代码之间存在细微差别:

static DateTimeFormatter HOUR_FORMAT = DateTimeFormatter.ofPattern("h:mm a", Locale.ENGLISH);

static DateTimeFormatter MDY_FORMAT = DateTimeFormatter.ofPattern("M/d/yyyy");

public String calendar(ZonedDateTime dt) {
    StringBuilder sb = new StringBuilder();

    // check difference in days from today, considering just the date (ignoring the hours) 
    long days = ChronoUnit.DAYS.between(LocalDate.now(), dt.toLocalDate());
    if (days == 0) { // today
        sb.append("Today ");
    } else if (days == 1) { // tomorrow
        sb.append("Tomorrow ");
    } else if (days == -1) { // yesterday
        sb.append("Yesterday ");
    } else if (days > 0 && days < 7) { // next week
        sb.append(dt.getDayOfWeek().getDisplayName(TextStyle.FULL, Locale.ENGLISH)).append(" ");
    } else if (days < 0 && days > -7) { // last week
        sb.append("Last ").append(dt.getDayOfWeek().getDisplayName(TextStyle.FULL, Locale.ENGLISH)).append(" ");
    }

    if (Math.abs(days) < 7) {  // difference is less than a week, append current time
        sb.append("at ").append(dt.format(HOUR_FORMAT));
    } else { // more than a week of difference
        sb.append(dt.format(MDY_FORMAT));
    }

    return sb.toString();
}

I used a ZonedDateTime , which is an equivalent of Joda's DateTime (it represents a date and time in a timezone). 我使用了ZonedDateTime它等效于Joda的DateTime (它表示时区中的日期和时间)。

When calling DAYS.between , I converted it to a LocalDate , so the comparison considers only the date (day/month/year). 当调用DAYS.between ,我将其转换为LocalDate ,因此比较仅考虑日期(日/月/年)。 If I used a ZonedDateTime instead, the time would also be considered, so the result would be 1 day only if it has passed more than 24 hours (so you can change it according to your needs). 如果我改用ZonedDateTime ,那么还将考虑时间,因此,只有经过24小时以上(因此您可以根据需要更改),结果才是1天。

Note that I also had to create 2 instances of DateTimeFormatter . 请注意,我还必须创建2个DateTimeFormatter实例。 I created them outside of the method, so they can be reused (no need to create them all the time inside the method). 我在方法外部创建了它们,因此可以重用它们(无需始终在方法内部创建它们)。 Joda-Time didn't need it because the toString method in Joda's objects can take a pattern and internally creates a formatter, while in java.time API you must create the formatter explicity. Joda-Time不需要它,因为Joda对象中的toString方法可以采用某种模式并在内部创建格式化程序,而在java.time API中,您必须显式创建格式化程序。

Using it is also similar to Joda-Time: 使用它也类似于Joda-Time:

ZonedDateTime now = ZonedDateTime.now();
System.out.println(calendar(now.minusDays(10))); // 9/22/2017
System.out.println(calendar(now.minusDays(6))); // Last Tuesday at 9:34 AM
System.out.println(calendar(now.minusDays(3))); // Last Friday at 9:34 AM
System.out.println(calendar(now.minusDays(1))); // Yesterday at 9:34 AM
System.out.println(calendar(now)); // Today at 9:34 AM
System.out.println(calendar(now.plusDays(1))); // Tomorrow at 9:34 AM
System.out.println(calendar(now.plusDays(3))); // Thursday at 9:34 AM
System.out.println(calendar(now.plusDays(10))); // 10/12/2017

Just a note about timezones. 只是有关时区的注释。 In java.time API, all the date classes has a no-arg now() method that gets the current date/time in the JVM's default timezone. java.time API中,所有日期类都有一个no-arg now()方法,该方法获取JVM默认时区中的当前日期/时间。

Although it's very conveninent, it also has some drawbacks, because the default timezone can be changed without notice, even at runtime. 尽管它非常方便,但也有一些缺点,因为即使在运行时也可以在不通知的情况下更改默认时区。 It's better to specify which timezone you want, if possible. 如果可能的话,最好指定所需的时区。

The API uses IANA timezones names (always in the format Region/City , like America/New_York or Europe/Paris ). 该API使用IANA时区名称 (格式始终为Region/City ,例如America/New_YorkEurope/Paris )。 Avoid using the 3-letter abbreviations (like CET or EST ) because they are ambiguous and not standard . 避免使用3个字母的缩写(例如CETEST ),因为它们是模棱两可的并且不是标准的

You can get a list of available timezones (and choose the one that fits best your system) by calling ZoneId.getAvailableZoneIds() . 您可以通过调用ZoneId.getAvailableZoneIds()获得可用时区的列表(并选择最适合您的系统的时区ZoneId.getAvailableZoneIds()

To get the current date/time in a specific timezone, use the ZoneId class: 要获取特定时区中的当前日期/时间,请使用ZoneId类:

// get the current date/time in a specific timezone
ZonedDateTime.now(ZoneId.of("Europe/Paris"));

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM