我有一个函数,它接受一个自定义字符串并将其转换为Date。我的目标是存储今天的日期,但是使用字符串提供的自定义时间:分钟。
由于某种原因,调试器显示AM / PM最后切换(但流程正确)。当我传入12:05am
时,Date对象存储为PM值,而如果我传入12:05pm
,则Date对象存储为AM值。应该是相反的。
代码:
public class DateUtils {
private static final String AM_LOWERCASE = "am";
private static final String AM_UPPERCASE = "AM";
public static Date getDateFromTimeString(String timeStr) {
Calendar calendar = Calendar.getInstance();
if (StringUtils.hasText(timeStr)) {
if (timeStr.indexOf(AM_LOWERCASE) != -1 || timeStr.indexOf(AM_UPPERCASE) != -1) {
calendar.set(Calendar.AM_PM, Calendar.AM);
} else {
calendar.set(Calendar.AM_PM, Calendar.PM);
}
// Set custom Hours:Minutes on today's date, based on timeStr
String[] timeStrParts = timeStr.replaceAll("[a-zA-Z]", "").split(":");
calendar.set(Calendar.HOUR, Integer.valueOf(timeStrParts[0]));
calendar.set(Calendar.MINUTE, Integer.valueOf(timeStrParts[1]));
calendar.set(Calendar.SECOND, 0);
calendar.set(Calendar.MILLISECOND, 0);
}
return calendar.getTime();
}
}
调试器显示:
输入:12:05am -> Sun Dec 17 12:05:00 EST 2017
输入:12:05pm -> Mon Dec 18 00:05:00 EST 2017
应该与此相反。如果我使用SimpleDateFormat写回这些字符串,我会看到输入1在12:05 PM返回,输入2在12:05 AM返回。
此外,对于#2,日期不应该在一天前进。应该存储的日期是两个情况下的今天日期,上午12:05或下午12:05。
我错过了什么吗?目标:
12:05am -> Sun Dec 17 00:05:00 EST 2017
12:05pm -> Sun Dec 17 12:05:00 EST 2017
答案 0 :(得分:5)
问题是Calendar.HOUR
的值范围从0
到11
,而不是1
到12
。当您将小时设置为12
时,日历将其标准化为当天的另一半...即,您“溢出”到第二天的一半。
public static void main(String[] args)
{
Calendar c1 = Calendar.getInstance();
System.out.printf("Initial: %s\n",c1.getTime().toString());
c1.set(Calendar.AM_PM, Calendar.AM);
System.out.printf("Set(AM): %s\n",c1.getTime().toString());
c1.set(Calendar.HOUR, 12);
System.out.printf("Set(12): %s\n\n",c1.getTime().toString());
Calendar c2 = Calendar.getInstance();
System.out.printf("Initial: %s\n",c2.getTime().toString());
c2.set(Calendar.AM_PM, Calendar.PM);
System.out.printf("Set(PM): %s\n",c2.getTime().toString());
c2.set(Calendar.HOUR, 12);
System.out.printf("Set(12): %s\n\n",c2.getTime().toString());
}
输出
Initial: Sun Dec 17 17:53:52 PST 2017
Set(AM): Sun Dec 17 05:53:52 PST 2017
Set(12): Sun Dec 17 12:53:52 PST 2017
Initial: Sun Dec 17 17:53:52 PST 2017
Set(PM): Sun Dec 17 17:53:52 PST 2017
Set(12): Mon Dec 18 00:53:52 PST 2017
除此之外,您应该使用自Java 8以来已成为Java一部分的新Time类。它们取代了多年来已知不太理想的遗留类(即日历,日期等)。
正如@Andreas所建议的,以下是如何以现代方式解析它:
LocalTime.parse(
"12:05am",
new DateTimeFormatterBuilder().
parseCaseInsensitive().
appendPattern("hh:mma").
toFormatter(Locale.US));
答案 1 :(得分:2)
foreach (Action action in BackProp)
{
action();
}
You are using troublesome old date-time classes that are now legacy, supplanted by java.time classes.
ZonedDateTime.of(
LocalDate.now( ZoneId.of( "Africa/Casablanca" ) ) ,
LocalTime.parse( "12:05am".toUppercase() , DateTimeFormatter.ofPattern( "hh:mma" , Locale.US ) ) ,
ZoneId.of( "Africa/Casablanca" )
)
Your input strings use lowercase "am"/"pm" which are incorrect. Those letters are actually initial-letter abbreviations and so should be uppercase. We must force the uppercase to facilitate parsing.
java.time.LocalTime
You are inappropriately trying to represent a time-of-day with a date-time class. Instead use DateTimeFormatter f = DateTimeFormatter.ofPattern( "hh:mma" , Locale.US ) ;
LocalTime lt = LocalTime.parse( "12:05am".toUppercase() , f ) ;
class as it is meant for a time-of-day with no date and no zone/offset.
Getting the current date requires a time zone.
LocalTime
Combine to get a ZoneId z = ZoneId.of( "Pacific/Auckland" ) ;
LocalDate ld = LocalDate.now( z );
.
ZonedDateTime
If that time-of-day on that date in that zone is not valid because of anomalies such as Daylight Saving Time, java.time automatically adjusts. Read the doc to be sure you understand and agree with the adjustment algorithm.
答案 2 :(得分:1)
<label>Personal Skills</label>
<select multiple size=14 input type="text" id="skill1" name="skill1" class="form-control" value="<?php echo $out['skill1'];?>">
<option value="" disabled selected hidden>Select...</option>
<option value='=COMPASSIONATE'>COMPASSIONATE</option>
<option value='EFFECTIVE COMMUNICATOR'>EFFECTIVE COMMUNICATOR</option>
<option value='LEADERSHIP'>LEADERSHIP</option>
<option value='INSIGHTFUL'>INSIGHTFUL</option>
<option value='PERCEPTIVE'>PERCEPTIVE</option>
<option value='CREATIVE'>CREATIVE</option>
<option value='FLEXIBLE'>FLEXIBLE</option>
<option value='INNOVATIVE'>INNOVATIVE</option>
<option value='LOGICAL THINKING'>LOGICAL THINKING</option>
<option value='PROBLEM SOLVING'>PROBLEM SOLVING</option>
<option value='SOCIABLE'>SOCIABLE</option>
<option value='CONSISTENT'>CONSISTENT</option>
<option value='MARKETING'>MARKETING</option>
<option value='CRITICAL THINKING '>CRITICAL THINKING</option>
</select>
日期时间 API 及其格式化 API java.util
已过时且容易出错。建议完全停止使用它们并切换到 modern Date-Time API*。
SimpleDateFormat
操作执行 String
操作(例如正则表达式匹配、转大写、转小写等)可能容易出错且不完整。而是使用 DateTimeFormatterBuilder
,它允许一组丰富的选项(例如不区分大小写的解析、指定可选模式、使用默认值解析等)。
演示:
String
输出:
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
import java.util.Locale;
import java.util.stream.Stream;
public class Main {
public static void main(String[] args) {
DateTimeFormatter dtf = new DateTimeFormatterBuilder()
.parseCaseInsensitive() //To parse in case-insensitive way e.g. AM, am
.appendPattern("h:m[ ]a") // Notice single h and m and optional space in square bracket
.toFormatter(Locale.ENGLISH);
// Test
Stream.of(
"08:20 am",
"08:20 pm",
"08:20 AM",
"08:20 PM",
"8:20 am",
"08:5 pm",
"08:5pm",
"8:5am"
).forEach(s -> System.out.println(LocalTime.parse(s, dtf)));
}
}
请注意单个 08:20
20:20
08:20
20:20
08:20
20:05
20:05
08:05
和 h
,它们既适用于一位数,也适用于两位数的小时和分钟。另一件需要注意的事情是使用方括号指定的可选空间。您可以在单个 m
中指定许多可选模式。查看 this answer 演示 DateTimeFormatter
的一些更强大的功能。
使用 ZonedDateTime#of(LocalDate, LocalTime, ZoneId)
创建一个。
DateTimeFormatter
从 modern Date-Time API 中详细了解 String strTime = "08:20 am";
ZoneId tz = ZoneId.of("America/Los_Angeles");
System.out.println(ZonedDateTime.of(LocalDate.now(tz), LocalTime.parse(strTime, dtf), tz));
,Trail: Date Time*。
* 出于任何原因,如果您必须坚持使用 Java 6 或 Java 7,您可以使用 ThreeTen-Backport,它将大部分 java.time 功能向后移植到 Java 6 & 7. 如果您正在为 Android 项目工作并且您的 Android API 级别仍然不符合 Java-8,请检查 Java 8+ APIs available through desugaring 和 How to use ThreeTenABP in Android Project。