为啥我加了 10 分钟后月份变成了 50?

Posted

技术标签:

【中文标题】为啥我加了 10 分钟后月份变成了 50?【英文标题】:Why is the month changed to 50 after I added 10 minutes?为什么我加了 10 分钟后月份变成了 50? 【发布时间】:2012-02-21 01:45:11 【问题描述】:

我有这个日期对象:

SimpleDateFormat df = new SimpleDateFormat("yyyy-mm-dd HH:mm");
Date d1 = df.parse(interviewList.get(37).getTime());

d1 的值为Fri Jan 07 17:40:00 PKT 2011

现在我正在尝试在上面的日期上增加 10 分钟。

Calendar cal = Calendar.getInstance();
cal.setTime(d1);
cal.add(Calendar.MINUTE, 10);
String newTime = df.format(cal.getTime());

newTime 的值更改为 2011-50-07 17:50 但应该是07-01-2011 17:50

它正确地添加了分钟,但它也改变了月份,不知道为什么!

【问题讨论】:

Java , adding minutes to a Date , weird anomaly 的可能重复项 How do I add one month to current date in Java?的可能重复 对于该问题的新读者,我建议您不要使用SimpleDateFormatDateCalendar。这些类设计不佳且过时已久,尤其是第一个类是出了名的麻烦。而是使用来自java.time, the modern Java date and time API 的LocalDateTimeDateTimeFormatter 我不同意建议的重复项。这个问题与SimpleDateFormat ignoring month when parsing 有关,但不是它的副本。它可能会,也可能不会被认为是后来的When Using Date Picker In android It is Picking the Wrong Date [duplicate] 的副本。 【参考方案1】:

对于 android 开发人员,这是一个使用 @jeznag 答案扩展的 kotlin 实现

 fun Date.addMinutesToDate(minutes: Int): Date 
    val minuteMillis: Long = 60000 //millisecs
    val curTimeInMs: Long = this.time
    val result = Date(curTimeInMs + minutes * minuteMillis)
    this.time = result.time
    return this

检查功能是否按预期工作的单元测试

@Test
fun `test minutes are added to date`() 
    //given
    val date = SimpleDateFormat("dd-MM-yyyy hh:mm").parse("29-04-2021 23:00")
    //when
    date?.addMinutesToDate(45)
    //then
    val calendar = Calendar.getInstance()
    calendar.time = date
    assertEquals(29, calendar[Calendar.DAY_OF_MONTH])
    assertEquals(23, calendar[Calendar.HOUR_OF_DAY])
    assertEquals(45, calendar[Calendar.MINUTE])

【讨论】:

【参考方案2】:

可以在没有常量的情况下完成(比如 3600000 ms 是 1h)

public static Date addMinutesToDate(Date date, int minutes) 
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(Calendar.MINUTE, minutes);
        return calendar.getTime();
    

public static Date addHoursToDate(Date date, int hours) 
    Calendar calendar = Calendar.getInstance();
    calendar.setTime(date);
    calendar.add(Calendar.HOUR_OF_DAY, hours);
    return calendar.getTime();

使用示例:

System.out.println(new Date());
System.out.println(addMinutesToDate(new Date(), 5));

Tue May 26 16:16:14 CEST 2020
Tue May 26 16:21:14 CEST 2020

【讨论】:

这些可怕的日期时间类在几年前被现代的 java.time 类所取代,随着 JSR 310 的采用。【参考方案3】:

为了避免任何依赖,您可以使用 java.util.Calendar,如下所示:

    Calendar now = Calendar.getInstance();
    now.add(Calendar.MINUTE, 10);
    Date teenMinutesFromNow = now.getTime();

在 Java 8 中我们有新的 API:

    LocalDateTime dateTime = LocalDateTime.now().plus(Duration.of(10, ChronoUnit.MINUTES));
    Date tmfn = Date.from(dateTime.atZone(ZoneId.systemDefault()).toInstant());

【讨论】:

【参考方案4】:

tl;博士

LocalDateTime.parse( 
    "2016-01-23 12:34".replace( " " , "T" )
)
.atZone( ZoneId.of( "Asia/Karachi" ) )
.plusMinutes( 10 )

java.time

使用优秀的 java.time 类进行日期时间工作。这些类取代了麻烦的旧日期时间类,例如 java.util.Datejava.util.Calendar

ISO 8601

java.time 类默认使用标准ISO 8601 格式来解析/生成日期时间值字符串。要使您的输入字符串符合要求,请将中间的空格替换为T

String input = "2016-01-23 12:34" ;
String inputModified = input.replace( " " , "T" );

LocalDateTime

将您的输入字符串解析为 LocalDateTime,因为它缺少有关时区或与 UTC 的偏移量的任何信息。

LocalDateTime ldt = LocalDateTime.parse( inputModified );

加十分钟。

LocalDateTime ldtLater = ldt.plusMinutes( 10 );

ldt.toString(): 2016-01-23T12:34

ldtLater.toString(): 2016-01-23T12:44

见live code in IdeOne.com。

LocalDateTime 没有时区,所以它确实代表时间线上的一个点。应用时区以转换为实际时刻。以continent/region 的格式指定proper time zone name,例如America/MontrealAfrica/Casablanca、或Pacific/Auckland、或Asia/Karachi。切勿使用 3-4 个字母的缩写,例如 ESTISTPKT,因为它们不是真正的时区,没有标准化,甚至不是唯一的 (!)。

ZonedDateTime

如果您知道此值的预期时区,请应用ZoneId 以获取ZonedDateTime

ZoneId z = ZoneId.of( "Asia/Karachi" );
ZonedDateTime zdt = ldt.atZone( z );

zdt.toString(): 2016-01-23T12:44+05:00[亚洲/卡拉奇]

异常

考虑是在添加时区之前还是之后添加这十分钟。由于夏令时 (DST) 等异常会改变wall-clock time,您可能会得到非常不同的结果。

加区前10分钟还是加区后加10分钟取决于你的业务场景和规则的含义。

提示:当您打算在时间轴上显示特定时刻时,始终保留时区信息。不要像输入数据一样丢失该信息。 12:34 的值是指巴基斯坦的中午、法国的中午还是魁北克的中午?如果您指的是巴基斯坦的中午,请至少包含与 UTC 的偏移量 (+05:00),最好是时区名称 (Asia/Karachi)。

Instant

如果您想要通过UTC 的镜头看到的相同时刻,请提取InstantInstant 类代表UTC 中时间线上的时刻,分辨率为nanoseconds(最多九 (9) 位小数)。

Instant instant = zdt.toInstant();

转换

尽可能避免使用麻烦的旧日期时间类。但是,如果必须,您可以转换。调用添加到旧类的新方法。

java.util.Date utilDate = java.util.Date.from( instant );

关于java.time

java.time 框架内置于 Java 8 及更高版本中。这些类取代了麻烦的旧 legacy 日期时间类,例如 java.util.DateCalendarSimpleDateFormat

Joda-Time 项目现在位于maintenance mode,建议迁移到 java.time。

要了解更多信息,请参阅Oracle Tutorial。并在 Stack Overflow 上搜索许多示例和解释。规格为JSR 310。

从哪里获得 java.time 类?

Java SE 8SE 9 及更高版本 内置。 标准 Java API 的一部分,带有捆绑实现。 Java 9 添加了一些小功能和修复。 Java SE 6SE 7 大部分 java.time 功能都在ThreeTen-Backport 中向后移植到 Java 6 和 7。 Android ThreeTenABP 项目专门针对 Android 改编 ThreeTen-Backport(如上所述)。 见How to use…

ThreeTen-Extra 项目通过附加类扩展了 java.time。该项目是未来可能添加到 java.time 的试验场。您可以在这里找到一些有用的类,例如IntervalYearWeekYearQuarter 和more。

【讨论】:

【参考方案5】:

一旦你解析了日期,我会使用这个实用函数来添加小时、分钟或秒:

public class DateTimeUtils 
    private static final long ONE_HOUR_IN_MS = 3600000;
    private static final long ONE_MIN_IN_MS = 60000;
    private static final long ONE_SEC_IN_MS = 1000;

    public static Date sumTimeToDate(Date date, int hours, int mins, int secs) 
        long hoursToAddInMs = hours * ONE_HOUR_IN_MS;
        long minsToAddInMs = mins * ONE_MIN_IN_MS;
        long secsToAddInMs = secs * ONE_SEC_IN_MS;
        return new Date(date.getTime() + hoursToAddInMs + minsToAddInMs + secsToAddInMs);
    

添加较长时间段时要小心,1 天并不总是 24 小时(夏令时类型的调整、闰秒等),为此建议使用 Calendar

【讨论】:

【参考方案6】:

您的问题是您使用的是mm。你应该使用MMMM 是月份,mm 是分钟。试试yyyy-MM-dd HH:mm

其他方法:

可以这么简单(其他选项是使用joda-time)

static final long ONE_MINUTE_IN_MILLIS=60000;//millisecs

Calendar date = Calendar.getInstance();
long t= date.getTimeInMillis();
Date afterAddingTenMins=new Date(t + (10 * ONE_MINUTE_IN_MILLIS));

【讨论】:

谢谢,我试过了,日期是正确的,但是当我尝试将它更改为字符串时,它给了我同样的错误结果 String newTime= df.format(afterAddingTenMins);它给了我 2011-50-07 17:50 ,我必须将它转换为字符串,任何建议 @junaidp 你使用了后面的代码,但忽略了前面的解决方案? 错误 - 使用小写 mm 而不是大写 MM - 可能也意味着解析的日期,Fri Jan 07 17:40:00 PKT 2011,不正确。 SimpleDateFormat 不会从原始字符串中选择月份,默认月份为一月。【参考方案7】:

仅适用于任何有兴趣的人。我正在开发一个需要类似功能的 ios 项目,所以我结束了将@jeznag 的答案移植到 swift

private func addMinutesToDate(minutes: Int, beforeDate: NSDate) -> NSDate 
    var SIXTY_SECONDS = 60

    var m = (Double) (minutes * SIXTY_SECONDS)
    var c =  beforeDate.timeIntervalSince1970  + m
    var newDate = NSDate(timeIntervalSince1970: c)

    return newDate

【讨论】:

Date from Swift 已经有类似的内置函数,例如 Date(timeInterval: , since: )【参考方案8】:

为我工作 DateUtils

//import
import org.apache.commons.lang.time.DateUtils

...

        //Added and removed minutes to increase current range dates
        Date horaInicialCorteEspecial = DateUtils.addMinutes(new Date(corteEspecial.horaInicial.getTime()),-1)
        Date horaFinalCorteEspecial = DateUtils.addMinutes(new Date(corteEspecial.horaFinal.getTime()),1)

【讨论】:

此答案对one from last year posted by alireza alallah 有何改进?此外,问题指的是分钟,而不是秒。【参考方案9】:

实现@Pangea答案的便捷方法:

/*
*  Convenience method to add a specified number of minutes to a Date object
*  From: http://***.com/questions/9043981/how-to-add-minutes-to-my-date
*  @param  minutes  The number of minutes to add
*  @param  beforeTime  The time that will have minutes added to it
*  @return  A date object with the specified number of minutes added to it 
*/
private static Date addMinutesToDate(int minutes, Date beforeTime)
    final long ONE_MINUTE_IN_MILLIS = 60000;//millisecs

    long curTimeInMs = beforeTime.getTime();
    Date afterAddingMins = new Date(curTimeInMs + (minutes * ONE_MINUTE_IN_MILLIS));
    return afterAddingMins;

【讨论】:

【参考方案10】:

你可以使用 org.apache.commons.lang3.time 包中的 DateUtils 类

int addMinuteTime = 5;
Date targetTime = new Date(); //now
targetTime = DateUtils.addMinutes(targetTime, addMinuteTime); //add minute

【讨论】:

对于处理旧版本 DateUtils 的人,它存在于包中 -> org.apache.commons.lang.time.DateUtils【参考方案11】:

使用这种格式,

SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm");

mm 表示分钟,MM 表示 mounth

【讨论】:

【参考方案12】:

您的 SimpleDateFormat 的模式有误。应该是

SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm");

【讨论】:

【参考方案13】:

这是错误的指定:

SimpleDateFormat df = new SimpleDateFormat("yyyy-mm-dd HH:mm");

您使用的是分钟而不是月份 (MM)

【讨论】:

以上是关于为啥我加了 10 分钟后月份变成了 50?的主要内容,如果未能解决你的问题,请参考以下文章

为啥linux显示自己的权限不够???我加了sudo了,看下面。。。

为啥ps给图片加水印后像素会变大

MySQL分区表-按月份归类

熊猫热土-环汶川50公里越野赛赛记

(无)

九月份技术指标