日历日添加无法正常工作

时间:2020-09-07 12:52:58

标签: android date kotlin calendar

我正在尝试编写一种算法,该算法基于1到31(一个月中的一天)之间的数字,它将返回该日期/数字之前时刻的毫秒数。 该算法将始终使用今天的日期。

示例: 输入5 输出:1601845199000,即2020年10月4日23:59:59

================

输入:31 输出:1601499599000,这是2020年9月30日在23:59:59

因为月份没有31天,即使指定了31天,算法也会采用最接近的日期。

2月29日(29/30)也是如此

    val calendar = Calendar.getInstance()        
    calendar.set(Calendar.HOUR_OF_DAY, 23)
    calendar.set(Calendar.MINUTE, 59)
    calendar.set(Calendar.SECOND, 59)
    calendar.clear(Calendar.MILLISECOND)

    val lastDayNumber = 31

    var found = false
    while (!found) {
        if (calendar.get(Calendar.DAY_OF_MONTH) <= lastDayNumber) {
            found = true
        }

        if (calendar.get(Calendar.DAY_OF_MONTH) < lastDayNumber) {
            calendar.add(Calendar.DATE, 1)
        }
    }

问题是calendar.add(Calendar.DATE, 1)根本无法工作。

此方法应找到将来给出的数字的前一天。我想念什么吗?我已经阅读了文档和其他StackOverflow答案,但仍然无法理解。

Edit1:我也尝试过calendar.add(Calendar.DAY_OF_MONTH, 1)和+1,但是-1工作得很好。

Edit2:

看着GregorianCalendar.java,我看到以下内容:

        // Handle week, day and AM_PM fields which involves
        // time zone offset change adjustment. Convert the
        // given amount to the number of days.
        case WEEK_OF_YEAR:
        case WEEK_OF_MONTH:
        case DAY_OF_WEEK_IN_MONTH:
            delta *= 7;
            break;

        case DAY_OF_MONTH: // synonym of DATE
        case DAY_OF_YEAR:
        case DAY_OF_WEEK:
            break;

如果我以WEEL_OF_YEAR为例,则相同的代码还将在week_of_month和day_of_week_in_month运行,因为不间断,所有3个字段都通过相同的代码运行。

但是,我发现绝对没有代码可以在DAY_OF_MONTHDAY_OF_YEARDAY_OF_WEEK上运行。

P.S。我找不到DATE字段

================================================ ===

使用LocalDateTime

fun getLastDayOfMonth(date: LocalDateTime): Long {
    val lastDayNumber = lastDay?.filter { it.isDigit() }!!.toInt()

    var found = false
    while (!found) {
        if (date.dayOfMonth <= lastDayNumber) {
            found = true
        } else {
            date.plusDays(1)
        }
    }

    return date.toEpochSecond(ZoneOffset.UTC)
}

date.plusDays(1) is not changing the date variable to be next day ...

2 个答案:

答案 0 :(得分:2)

您可以使用java.time,它为此提供了非常方便的方法。

请参见以下示例:

import java.time.LocalDate

fun main() {
    val fourDaysAgo = findDate(4)
    println(fourDaysAgo)
}

fun findDate(daysAgo: Long): LocalDate {
    return LocalDate.now().minusDays(daysAgo)
}

它输出4天前的日期(今天/ 2020-09-07执行)

2020-09-03

LocalDate.now()计算今天的日期(注意:仅是日期部分,不涉及一天中的时间,偏移量或时区),并返回具有方法LocalDate的{​​{1}}如有必要,可以通过调整月份和年份来正确计算之前的日期

如果您执行以下操作:

minusDays(long days)

输出为

println(LocalDate.of(2020, 1, 1).minusDays(1))

如果您还需要时间部分,甚至可能需要偏移量或时区来真正正确地减去天,小时,分钟或任何时间单位,请查看2019-12-31 中的其他类。

在您的问题下的以下评论之后,

编辑:
如果输入7,今天是9月7日,则应该是10月6日。如果输入8,则应该是9月7日(今天)

java.time

注意:我猜想输入月份少于今天的情况是因为您没有为它指定任何行为。该案件的处理方式与每月(争论和今天)的天数相同。

答案 1 :(得分:1)

这是我的去。像deHaar一样,我强烈建议您使用java.time(现代的Java日期和时间API)进行日期和时间工作。您尝试使用的Calendar类的设计很差,而且已经过时。

由于您希望将时间设为午夜前1秒钟,因此我们首先声明一个具有以下值的常量:

private static final Duration timeBeforeStartOfDay = Duration.ofSeconds(1); 

如果您希望有一天,可以很容易地将其更改为1分钟,1毫秒或1纳秒。

我们需要考虑一些极端情况。我认为这段代码可以做到:

    ZoneId zone = ZoneId.systemDefault();
    int dayNumber = 31;
    
    LocalDate today = LocalDate.now(zone);

    YearMonth ym = YearMonth.from(today);
    if (dayNumber <= today.getDayOfMonth()) {
        // Next month
        ym = ym.plusMonths(1);
    }
    ZonedDateTime targetDateTime;
    if (dayNumber > ym.lengthOfMonth()) {
        // Use end of month
        targetDateTime = ym.plusMonths(1)
                .atDay(1)
                .atStartOfDay(zone)
                .minus(timeBeforeStartOfDay);
    } else {
        // Use day number
        targetDateTime = ym.atDay(dayNumber)
                .atStartOfDay(zone)
                .minus(timeBeforeStartOfDay);
    }
    long milliseconds = targetDateTime.toInstant().toEpochMilli();
    
    System.out.println("Target date and time: " + targetDateTime);
    System.out.println("Target milliseconds: " + milliseconds);

我们在哪个时区运行它会有所不同。我在欧洲/布加勒斯特时区运行过它,因为我想它可能是您的。今天(9月7日)的输出为:

Target date and time: 2020-09-30T23:59:59+03:00[Europe/Bucharest]
Target milliseconds: 1601499599000

链接: Oracle tutorial: Date Time解释了如何使用java.time。