如何获得当前周和月的第一天?

ces*_*nux 68 java android date

我有几个事件的日期,以毫秒 [1] 表示,我想知道哪些事件在当前周和当月,但我无法弄清楚如何获得第一天(日/月/年) )运行周并将其转换为毫秒,同一个月的第一天.

[1]Since January 1, 1970, 00:00:00 GMT
Run Code Online (Sandbox Code Playgroud)

COM*_*ROM 146

本周以毫秒为单位:

// get today and clear time of day
Calendar cal = Calendar.getInstance();
cal.set(Calendar.HOUR_OF_DAY, 0); // ! clear would not reset the hour of day !
cal.clear(Calendar.MINUTE);
cal.clear(Calendar.SECOND);
cal.clear(Calendar.MILLISECOND);

// get start of this week in milliseconds
cal.set(Calendar.DAY_OF_WEEK, cal.getFirstDayOfWeek());
System.out.println("Start of this week:       " + cal.getTime());
System.out.println("... in milliseconds:      " + cal.getTimeInMillis());

// start of the next week
cal.add(Calendar.WEEK_OF_YEAR, 1);
System.out.println("Start of the next week:   " + cal.getTime());
System.out.println("... in milliseconds:      " + cal.getTimeInMillis());
Run Code Online (Sandbox Code Playgroud)

本月以毫秒为单位:

// get today and clear time of day
Calendar cal = Calendar.getInstance();
cal.set(Calendar.HOUR_OF_DAY, 0); // ! clear would not reset the hour of day !
cal.clear(Calendar.MINUTE);
cal.clear(Calendar.SECOND);
cal.clear(Calendar.MILLISECOND);

// get start of the month
cal.set(Calendar.DAY_OF_MONTH, 1);
System.out.println("Start of the month:       " + cal.getTime());
System.out.println("... in milliseconds:      " + cal.getTimeInMillis());

// get start of the next month
cal.add(Calendar.MONTH, 1);
System.out.println("Start of the next month:  " + cal.getTime());
System.out.println("... in milliseconds:      " + cal.getTimeInMillis());
Run Code Online (Sandbox Code Playgroud)

  • @COMEFROM 为什么你建议使用 clear?如果我使用有什么好处,如果我不使用会出现什么错误? (2认同)

Bal*_*usC 23

一周的第一天可以通过以下方式确定java.util.Calendar:

Calendar calendar = Calendar.getInstance();
calendar.clear();
calendar.setTimeInMillis(timestamp);
while (calendar.get(Calendar.DAY_OF_WEEK) > calendar.getFirstDayOfWeek()) {
    calendar.add(Calendar.DATE, -1); // Substract 1 day until first day of week.
}
long firstDayOfWeekTimestamp = calendar.getTimeInMillis();
Run Code Online (Sandbox Code Playgroud)

每月的第一天可以确定如下:

Calendar calendar = Calendar.getInstance();
calendar.clear();
calendar.setTimeInMillis(timestamp);
while (calendar.get(Calendar.DATE) > 1) {
    calendar.add(Calendar.DATE, -1); // Substract 1 day until first day of month.
}
long firstDayOfMonthTimestamp = calendar.getTimeInMillis();
Run Code Online (Sandbox Code Playgroud)

非常详细,是的.


Java 7将带有一个改进的日期和时间API(JSR-310).如果你还没有切换,那么你可以使用JodaTime,这使得它不那么复杂:

DateTime dateTime = new DateTime(timestamp);
long firstDayOfWeekTimestamp = dateTime.withDayOfWeek(1).getMillis();
Run Code Online (Sandbox Code Playgroud)

DateTime dateTime = new DateTime(timestamp);
long firstDayOfMonthTimestamp = dateTime.withDayOfMonth(1).getMillis();
Run Code Online (Sandbox Code Playgroud)

  • 虽然请记住,jodatime可能会将您的30kb应用程序变成300kb的应用程序. (2认同)

Bas*_*que 13

java.time

Java 8及更高版本中的java.time框架取代了旧的java.util.Date/.Calendar类.旧的课程被证明是麻烦,混乱和有缺陷的.避免他们.

java.time框架的灵感来自于高度成功的Joda-Time库,由JSR 310定义,由ThreeTen-Extra项目扩展,并在教程中进行了解释.

Instant

Instant类代表在时间轴上一个时刻UTC.

java.time框架的分辨率为纳秒,或小数秒的9位数.毫秒只是小数秒的3位数.由于毫秒分辨率很常见,因此java.time包含一个方便的工厂方法.

long millisecondsSinceEpoch = 1446959825213L;
Instant instant = Instant.ofEpochMilli ( millisecondsSinceEpoch );
Run Code Online (Sandbox Code Playgroud)

millisecondsSinceEpoch:1446959825213即时:2015-11-08T05:17:05.213Z

ZonedDateTime

要考虑当前周和当月,我们需要应用特定时区.

ZoneId zoneId = ZoneId.of ( "America/Montreal" );
ZonedDateTime zdt = ZonedDateTime.ofInstant ( instant , zoneId );
Run Code Online (Sandbox Code Playgroud)

在zoneId:America/Montreal,即:2015-11-08T00:17:05.213-05:00 [America/Montreal]

半开

在日期时间工作中,我们通常使用半开放方法来定义时间跨度.开头是包容性的,而结尾是独家的.而不是试图确定一周(或月)结束的最后一个瞬间,我们得到的第一个瞬间以下星期(或月).所以一个星期从周一的第一时刻运行,并上升到但不包括在第一时刻以下星期一.

我们是一周的第一天,也是最后一天.java.time框架包括用于该with方法和ChronoField枚举的工具.

默认情况下,java.time使用ISO 8601标准.所以星期一是一周的第一天(1),星期日是最后一天(7).

ZonedDateTime firstOfWeek = zdt.with ( ChronoField.DAY_OF_WEEK , 1 ); // ISO 8601, Monday is first day of week.
ZonedDateTime firstOfNextWeek = firstOfWeek.plusWeeks ( 1 );
Run Code Online (Sandbox Code Playgroud)

那个星期从:2015-11-02T00:17:05.213-05:00 [美国/蒙特利尔]到2015-11-09T00:17:05.213-05:00 [美国/蒙特利尔]

哎呀!查看这些值的时间.我们想要一天的第一时刻.一天的第一时刻并不总是00:00:00.000因为夏令时(DST)或其他异常现象.所以我们应该让java.time代表我们进行调整.要做到这一点,我们必须通过LocalDate课程.

ZonedDateTime firstOfWeek = zdt.with ( ChronoField.DAY_OF_WEEK , 1 ); // ISO 8601, Monday is first day of week.
firstOfWeek = firstOfWeek.toLocalDate ().atStartOfDay ( zoneId );
ZonedDateTime firstOfNextWeek = firstOfWeek.plusWeeks ( 1 );
Run Code Online (Sandbox Code Playgroud)

那个星期从:2015-11-02T00:00-05:00 [美国/蒙特利尔]到2015-11-09T00:00-05:00 [美国/蒙特利尔]

同月也一样.

ZonedDateTime firstOfMonth = zdt.with ( ChronoField.DAY_OF_MONTH , 1 );
firstOfMonth = firstOfMonth.toLocalDate ().atStartOfDay ( zoneId );
ZonedDateTime firstOfNextMonth = firstOfMonth.plusMonths ( 1 );
Run Code Online (Sandbox Code Playgroud)

该月的运行时间为:2015-11-01T00:00-04:00 [美国/蒙特利尔]至2015-12-01T00:00-05:00 [美国/蒙特利尔]

YearMonth

查看一对时刻是否在同一个月的另一种方法是检查相同的YearMonth值.

例如,假设thisZdt并且thatZdt都是ZonedDateTime对象:

boolean inSameMonth = YearMonth.from( thisZdt ).equals( YearMonth.from( thatZdt ) ) ;
Run Code Online (Sandbox Code Playgroud)

毫秒

我强烈建议不要在几毫秒之内完成你的日期工作.这确实是日期时间类往往在内部工作的方式,但我们有一些原因.处理来自时代的计数是笨拙的,因为人们无法理解这些值,因此调试和记录很困难且容易出错.而且,正如我们已经看到的,可能会有不同的决议; 旧的Java类和Joda-Time库使用毫秒,而像Postgres这样的数据库使用微秒,现在java.time使用纳秒.

你会处理文本作为位,还是你让类,如String,StringBufferStringBuilder处理这样的细节?

但是,如果你坚持,从一个ZonedDateTime得到一个Instant,并从那里得到一个毫秒计数从纪元.但请记住,此调用可能意味着数据丢失.您ZonedDateTime/中可能包含的任何微秒或纳秒Instant将被截断(丢失).

long millis = firstOfWeek.toInstant().toEpochMilli();  // Possible data loss.
Run Code Online (Sandbox Code Playgroud)


小智 13

您可以使用该java.time包(从 Java8 起)来获取日/周/月的开始/结束。
下面的 util 类示例:

import org.junit.Test;

import java.time.DayOfWeek;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalAdjusters;
import java.util.Date;

public class DateUtil {
    private static final ZoneId DEFAULT_ZONE_ID = ZoneId.of("UTC");

    public static LocalDateTime startOfDay() {
        return LocalDateTime.now(DEFAULT_ZONE_ID).with(LocalTime.MIN);
    }

    public static LocalDateTime endOfDay() {
        return LocalDateTime.now(DEFAULT_ZONE_ID).with(LocalTime.MAX);
    }

    public static boolean belongsToCurrentDay(final LocalDateTime localDateTime) {
        return localDateTime.isAfter(startOfDay()) && localDateTime.isBefore(endOfDay());
    }

    //note that week starts with Monday
    public static LocalDateTime startOfWeek() {
        return LocalDateTime.now(DEFAULT_ZONE_ID)
                .with(LocalTime.MIN)
                .with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY));
    }

    //note that week ends with Sunday
    public static LocalDateTime endOfWeek() {
        return LocalDateTime.now(DEFAULT_ZONE_ID)
                .with(LocalTime.MAX)
                .with(TemporalAdjusters.nextOrSame(DayOfWeek.SUNDAY));
    }

    public static boolean belongsToCurrentWeek(final LocalDateTime localDateTime) {
        return localDateTime.isAfter(startOfWeek()) && localDateTime.isBefore(endOfWeek());
    }

    public static LocalDateTime startOfMonth() {
        return LocalDateTime.now(DEFAULT_ZONE_ID)
                .with(LocalTime.MIN)
                .with(TemporalAdjusters.firstDayOfMonth());
    }

    public static LocalDateTime endOfMonth() {
        return LocalDateTime.now(DEFAULT_ZONE_ID)
                .with(LocalTime.MAX)
                .with(TemporalAdjusters.lastDayOfMonth());
    }

    public static boolean belongsToCurrentMonth(final LocalDateTime localDateTime) {
        return localDateTime.isAfter(startOfMonth()) && localDateTime.isBefore(endOfMonth());
    }

    public static long toMills(final LocalDateTime localDateTime) {
        return localDateTime.atZone(DEFAULT_ZONE_ID).toInstant().toEpochMilli();
    }

    public static Date toDate(final LocalDateTime localDateTime) {
        return Date.from(localDateTime.atZone(DEFAULT_ZONE_ID).toInstant());
    }

    public static String toString(final LocalDateTime localDateTime) {
        return localDateTime.format(DateTimeFormatter.ISO_DATE_TIME);
    }

    @Test
    public void test() {
        //day
        final LocalDateTime now = LocalDateTime.now();
        System.out.println("Now: " + toString(now) + ", in mills: " + toMills(now));
        System.out.println("Start of day: " + toString(startOfDay()));
        System.out.println("End of day: " + toString(endOfDay()));
        System.out.println("Does '" + toString(now) + "' belong to the current day? > " + belongsToCurrentDay(now));
        final LocalDateTime yesterday = now.minusDays(1);
        System.out.println("Does '" + toString(yesterday) + "' belong to the current day? > " + belongsToCurrentDay(yesterday));
        final LocalDateTime tomorrow = now.plusDays(1);
        System.out.println("Does '" + toString(tomorrow) + "' belong to the current day? > " + belongsToCurrentDay(tomorrow));
        //week
        System.out.println("Start of week: " + toString(startOfWeek()));
        System.out.println("End of week: " + toString(endOfWeek()));
        System.out.println("Does '" + toString(now) + "' belong to the current week? > " + belongsToCurrentWeek(now));
        final LocalDateTime previousWeek = now.minusWeeks(1);
        System.out.println("Does '" + toString(previousWeek) + "' belong to the current week? > " + belongsToCurrentWeek(previousWeek));
        final LocalDateTime nextWeek = now.plusWeeks(1);
        System.out.println("Does '" + toString(nextWeek) + "' belong to the current week? > " + belongsToCurrentWeek(nextWeek));
        //month
        System.out.println("Start of month: " + toString(startOfMonth()));
        System.out.println("End of month: " + toString(endOfMonth()));
        System.out.println("Does '" + toString(now) + "' belong to the current month? > " + belongsToCurrentMonth(now));
        final LocalDateTime previousMonth = now.minusMonths(1);
        System.out.println("Does '" + toString(previousMonth) + "' belong to the current month? > " + belongsToCurrentMonth(previousMonth));
        final LocalDateTime nextMonth = now.plusMonths(1);
        System.out.println("Does '" + toString(nextMonth) + "' belong to the current month? > " + belongsToCurrentMonth(nextMonth));
    }
}
Run Code Online (Sandbox Code Playgroud)

测试输出:

Now: 2020-02-16T22:12:49.957, in mills: 1581891169957
Start of day: 2020-02-16T00:00:00
End of day: 2020-02-16T23:59:59.999999999
Does '2020-02-16T22:12:49.957' belong to the current day? > true
Does '2020-02-15T22:12:49.957' belong to the current day? > false
Does '2020-02-17T22:12:49.957' belong to the current day? > false
Start of week: 2020-02-10T00:00:00
End of week: 2020-02-16T23:59:59.999999999
Does '2020-02-16T22:12:49.957' belong to the current week? > true
Does '2020-02-09T22:12:49.957' belong to the current week? > false
Does '2020-02-23T22:12:49.957' belong to the current week? > false
Start of month: 2020-02-01T00:00:00
End of month: 2020-02-29T23:59:59.999999999
Does '2020-02-16T22:12:49.957' belong to the current month? > true
Does '2020-01-16T22:12:49.957' belong to the current month? > false
Does '2020-03-16T22:12:49.957' belong to the current month? > false
Run Code Online (Sandbox Code Playgroud)


alc*_*san 12

注意!

while (calendar.get(Calendar.DAY_OF_WEEK) > calendar.getFirstDayOfWeek()) {
    calendar.add(Calendar.DATE, -1); // Substract 1 day until first day of week.
}
Run Code Online (Sandbox Code Playgroud)

是个好主意,但有一些问题:例如,我来自乌克兰,我国的calendar.getFirstDayOfWeek()是2(星期一).今天是1(星期日).在这种情况下,没有调用calendar.add.

所以,正确的方法是将">"更改为"!=":

while (calendar.get(Calendar.DAY_OF_WEEK) != calendar.getFirstDayOfWeek()) {...
Run Code Online (Sandbox Code Playgroud)