为什么Java';s Calendar date将小时转换为日期时将其重置为另一个值?
我想在2020年10月26日做一个简单的脚本,每10分钟设置一次时间。为什么Java';s Calendar date将小时转换为日期时将其重置为另一个值?,java,Java,我想在2020年10月26日做一个简单的脚本,每10分钟设置一次时间。 我的循环如下所示。 然而,即使当我输出'time'变量时,时间通常看起来是正确的,然后我将其转换为Date对象,并对该'd'变量执行toString(),然后它似乎将其转换为另一个时间。如果您想看到它在联机java编译器上运行,您可以在此处看到它的运行: 你可以看到它做一些奇怪的事情,比如: 上午0:00 星期一10月26日10:00:00格林威治标准时间2020 上午0:10 2020年10月26日星期一10:10:00
我的循环如下所示。
然而,即使当我输出'time'变量时,时间通常看起来是正确的,然后我将其转换为Date对象,并对该'd'变量执行toString(),然后它似乎将其转换为另一个时间。如果您想看到它在联机java编译器上运行,您可以在此处看到它的运行:
你可以看到它做一些奇怪的事情,比如:
上午0:00
星期一10月26日10:00:00格林威治标准时间2020
上午0:10
2020年10月26日星期一10:10:00格林尼治标准时间
…
下午12:00
星期一10月26日22:00:00格林威治标准时间2020
下午12:10
…
星期一10月26日22:10:00格林威治标准时间2020 一件不同寻常的事情是,我将在IDE中设置一个12小时的断点。。。如果我调试缓慢,它将设置正确的时间。然后,我将删除断点并播放脚本的其余部分,然后时间再次不正确。我在Java中还没有见过非常不寻常的行为。
我可以这样做来重置小时数(或使用不同的技术): 但我现在更想弄清楚为什么Java会这样做
for(int hour=0; hour < 24; hour++ ) {
for(int minute = 0; minute < 6; minute++) {
String str_min = minute==0 ? "00" : String.valueOf(minute*10);
String time = String.valueOf( hour > 12 ? hour-12 : hour) +":"+ str_min +" "+ ((hour >= 12 ? Calendar.PM : Calendar.AM)==1 ? "PM" : "AM");
//note: got lazy and not outputting "00" for hour
System.out.println( time );
Calendar cal = Calendar.getInstance();
cal.set(Calendar.MONTH, 9); //Oct=9
cal.set(Calendar.DAY_OF_MONTH, 26);
cal.set(Calendar.YEAR, 2020);
cal.set(Calendar.HOUR_OF_DAY, hour );
cal.set(Calendar.MINUTE, minute*10 ); //0=0, 1=10, ... 5=50
cal.set(Calendar.AM_PM, (hour >= 12 ? Calendar.PM : Calendar.AM) );
cal.set(Calendar.SECOND, 0);
cal.set(Calendar.MILLISECOND, 0);
Date d = cal.getTime();
System.out.println( d.toString() );
}
}
for(int hour=0;hour<24;hour++){
对于(int-minute=0;minute<6;minute++){
String str_min=minute==0?“00”:String.valueOf(minute*10);
String time=String.valueOf(hour>12?hour-12:hour)+“:”+str_min++”((hour>=12?Calendar.PM:Calendar.AM)==1?:“PM”:“AM”);
//注意:变懒了,一个小时没有输出“00”
系统输出打印LN(时间);
Calendar cal=Calendar.getInstance();
校准设置(日历月,9);//十月=9
校准设置(日历日/月,26);
校准集(日历年,2020年);
校准设置(日历小时/天,小时);
cal.set(Calendar.MINUTE,MINUTE*10);//0=0,1=10,…5=50
校准设置(Calendar.AM\u PM,(小时>=12?Calendar.PM:Calendar.AM));
校准设置(日历秒,0);
校准设置(日历毫秒,0);
日期d=cal.getTime();
System.out.println(d.toString());
}
}
java.util.Date是个谎言。它不代表日期;它代表时间上的一个瞬间,它不知道时区,也不知道“小时”的概念。这就是为什么所有东西(除了基于epoch-millis的方法和构造函数)都被标记为不推荐使用
日历API试图解决这个问题,但它是一个非常可怕的API
改用java.time
。丑陋的API消失了,与旧的API不同,您拥有的类型实际上完全代表了您想要的。考虑到您没有在这里弄乱时区,您需要LocalDateTime
:
for (int hour = 0; hour < 24; hour++) {
for (int minute = 0; minute < 60; minute += 10) {
LocalDateTime ldt = LocalDateTime.of(2020, 10, 26, hour, minute, 0);
System.out.println(ldt);
// or better:
System.out.println(DateTimeFormatter.ISO_LOCAL_DATE_TIME.format(ldt));
}
}
for(int hour=0;hour<24;hour++){
对于(整数分钟=0;分钟<60;分钟+=10){
LocalDateTime ldt=LocalDateTime.of(2020,10,26,小时,分钟,0);
系统输出打印项次(ldt);
//或者更好:
System.out.println(DateTimeFormatter.ISO_LOCAL_DATE_TIME.format(ldt));
}
}
请注意在这个API中10月是如何的“10”,因为这个API不是疯狂的,例如。您可以在DTF中使用许多预定义的格式化程序中的任何一个,也可以使用一个模式编写自己的格式化程序,以精确地控制日期的呈现方式
如果你想代表其他事物,你可以这样做ZoneDateTime
按照人类的说法,指定一个特定的时间(比如:我和牙医约好了,他在罗马,时间是2020年11月2日下午2点一刻)。这样一个概念的要点是:如果罗马决定改变时区,那么你约会的实际时间应该随之改变
如果你想要一个瞬间,有instant
。这是一个特定的时刻(在过去或未来),在它发生之前,它不会改变剩余的毫秒数。即使面对各国改变其欧元区
LDT就是LDT:它只代表一年、一个月、一天、小时、分钟和秒,没有时区。tl;博士
避免遗留日期时间类
您正在使用可怕的日期时间类,这些类在几年前被java.time类取代。Sun、Oracle和the放弃了这些课程,您也应该放弃
与其尝试去理解那些糟糕的类,我建议您将精力投入到学习java.time上
使用java.time
当您需要当前日期时间时,更容易捕获即时
对象
请注意,java.time使用。我们生成一个新对象,而不是改变现有对象
今天每十分钟代表一个时刻:
ZoneId z = ZoneId.of( "Africa/Tunis" ) ; // Or "America/New_York", etc.
LocalDate today = LocalDate.now( z ) ;
您的代码做出了错误的假设。天或不总是24小时长。它们可能是23小时、25小时或其他长度。也不是每个时区的每一天都从00:00开始。让java.time确定一天中的第一个时刻
ZonedDateTime start = today.atStartOfDay( z ) ;
从第二天开始
ZonedDateTime stop = start.plusDays( 1 ) ;
循环10分钟的时间。将该区块表示为持续时间
Duration d = Duration.ofMinutes( 10 ) ;
List< ZonedDateTime > results = new ArrayList<>() ;
ZonedDateTime zdt = start ;
while( zdt.isBefore( stop ) )
{
results.add( zdt ) ;
zdt = zdt.plus( d ) ;
}
特别是,Locale.US
和FormatStyle.MEDIUM
可能适合您。开始做实验
关于java.time 该框架内置于Java8及更高版本中。这些类取代了麻烦的旧日期时间类,例如,& 要了解更多信息,请参阅。并搜索堆栈溢出以获得许多示例和解释。规格是 该项目现已启动,建议迁移到类 您可以直接与数据库交换java.time对象。使用兼容的或更高版本。不需要字符串,也不需要
java.sql.*
类。Hibernate5和JPA2.2支持java.time
从哪里获得java.time类
- 、和更高版本-标准Java API的一部分,带有捆绑实现。
- 带来了一些小功能和
ZonedDateTime stop = start.plusDays( 1 ) ;
Duration d = Duration.ofMinutes( 10 ) ; List< ZonedDateTime > results = new ArrayList<>() ; ZonedDateTime zdt = start ; while( zdt.isBefore( stop ) ) { results.add( zdt ) ; zdt = zdt.plus( d ) ; }
Locale locale = Locale.CANADA_FRENCH ; // Or Locale.US etc. DateTimeFormatter f = DateTimeFormatter.ofLocalizedDateTime( FormatStyle.FULL ).withLocale( locale ) ; String output = myZonedDateTime.format( f ) ;
- 带来了一些小功能和