本篇文章给大家谈谈将GregorianCalendar与SimpleDateFormat一起使用,同时本文还将给你拓展AndroidSimpleDateFormat,如何使用?、CalendarTim
本篇文章给大家谈谈将GregorianCalendar与SimpleDateFormat一起使用,同时本文还将给你拓展Android SimpleDateFormat,如何使用?、Calendar TimeZone SimpleDateFormat、DateTimeFormatter与SimpleDateFormat、DateTimeFormatter和SimpleDateFormat有什么区别?等相关知识,希望对各位有所帮助,不要忘了收藏本站喔。
本文目录一览:- 将GregorianCalendar与SimpleDateFormat一起使用
- Android SimpleDateFormat,如何使用?
- Calendar TimeZone SimpleDateFormat
- DateTimeFormatter与SimpleDateFormat
- DateTimeFormatter和SimpleDateFormat有什么区别?
将GregorianCalendar与SimpleDateFormat一起使用
因此,我一直在为这个(应该是)简单的练习而绞尽脑汁,以使该程序将日期字符串转换为GregorianCalendar
对象,对其进行格式化,并在完成后将其作为字符串再次返回。
这是程序的最后一点,它从文件中获取一小段文本,将其分解为单独的记录,然后将记录分解为单独的数据并将它们分配给个人对象。
我已经在多个位置检查了该代码,并且该代码完全执行了应该执行的操作,直到调用了format函数(该函数抛出)为止IllegalArgumentException
。为GergorianCalendar
对象分配了应该分配的值(尽管再次打印,如下所示),但是格式不会接受该对象进行格式化。
不幸的是,讲师不太确定如何使用GregorianCalendar
andSimpleDateFormat
(但还是指派我们与他们合作),并说:“只是Google……”,我尝试了一下,但发现没有任何帮助。
到目前为止,我的代码是:
public class DateUtil { public static GregorianCalendar convertFromDMY(String dd_mm_yy) throws ParseException{ // this actually works, got rid of the original code idea String[] splitDate = dd_mm_yy.split("-"); int days = Integer.parseInt(splitDate[0]); int month = Integer.parseInt(splitDate[1]); int year = Integer.parseInt(splitDate[2]); // Dates are going in right, checked in print statement, // but the object is not getting formatted… GregorianCalendar dateConverted = new GregorianCalendar(year, month, days); format(dateConverted); return dateConverted; } public static String format(GregorianCalendar date){ SimpleDateFormat fmt = new SimpleDateFormat("dd-MMM-yyyy"); String dateFormatted = fmt.format(date); return dateFormatted; }}
我得到的错误是:
线程“主”中的异常java.lang.IllegalArgumentException:无法将给定对象>格式化为日期 在java.text.DateFormat.format(DateFormat.java:281) 在java.text.Format.format(Format.java:140) 在lab2.DateUtil.format(DateUtil.java:26) 在lab2.DateUtil.convertFromDMY(DateUtil.java:19) 在lab2.Lab2.createStudent(Lab2.java:75) 在lab2.Lab2.main(Lab2.java:34)
还有一件事,我什至使用GregorianCalendar
对了吗?当我打印出该对象的值时(应该得到一个日期,对吗?),我得到以下信息:
java.util.GregorianCalendar [time = ?, areFieldsSet = false,areAllFieldsSet
= false,lenient = true,zone = sun.util.calendar.ZoneInfo [id =“ America /
Vancouver”,offset = -28800000,dstSavings = 3600000,useDaylight =
true,transitions = 189,lastRule = java.util.SimpleTimeZone [id = America /
Vancouver,offset = -28800000,dstSavings = 3600000,useDaylight =
true,startYear = 0,startMode = 3,startMonth = 2,startDay = 8, startDayOfWeek
= 1,startTime = 7200000,startTimeMode = 0,endMode = 3,endMonth = 10,endDay =
1,endDayOfWeek = 1,endTime = 7200000,endTimeMode = 0]],firstDayOfWeek =
1,minimalDaysInFirstWeek = 1,ERA = ?, YEAR = 1985,MONTH = 4,WEEK_OF_YEAR =
?, WEEK_OF_MONTH = ?, DAY_OF_MONTH = 22,DAY_OF_YEAR = ?, DAY_OF_WEEK = ?,
DAY_OF_WEEK_IN_MONTH = ?, AM_PM = 0,HOUR = 0,HOUR_OF_DAY = 0,MINUTE =
0,SECOND 0,MILLISECOND = ?, ZONE_OFFSET = ?, DST_OFFSET =?]
year,month和day_of_month值都是正确的,因为它们是我在创建该值时传递的数字。
想法,建议,我什至接近吗?
编辑
原来的问题已解决(感谢assylias!),但是我仍然无法正确打印,因为这两个函数没有链接,并且要求GregorianCalendar
从person对象中打印出日期值(因为birthdate是aGregorianCalendar
)。
更新的代码:
public class DateUtil { static SimpleDateFormat fmt = new SimpleDateFormat("dd-MMM-yyyy"); public static GregorianCalendar convertFromDMY(String dd_mm_yy) throws ParseException{ // this actually works, got rid of the original code idea String[] splitDate = dd_mm_yy.split("-"); int days = Integer.parseInt(splitDate[0]); int month = (Integer.parseInt(splitDate[1]) - 1); int year = Integer.parseInt(splitDate[2]); // dates go in properly GregorianCalendar dateConverted = new GregorianCalendar(year, month, days); String finalDate = format(dateConverted); return ; } public static String format(GregorianCalendar date) throws ParseException{ fmt.setCalendar(date); String dateFormatted = fmt.format(date.getTime()); System.out.println(dateFormatted); return dateFormatted; }}
最后编辑
好的,所以看来我是个白痴,并且不需要将两个DateUtil
功能链接在一起,而是串联使用它们。首先,将出生日期转换为aGregorianCalendar
并将其存储在person对象中。然后,在print语句中,只需简单地告诉程序在打印时格式化该日期即可。问题解决了。现在所有的作品都按照规范工作,我感到非常愚蠢,因为在DateUtil
上课的最后一天左右,我像鱼一样从水里飞起来,试图让它们同时工作。
感谢您对日期正确输入的所有帮助!
答案1
小编典典SimpleDateFormat.format()
方法采用a Date
作为参数。您可以通过调用其方法Date
从a
获取:Calendar``getTime()
public static String format(GregorianCalendar calendar) { SimpleDateFormat fmt = new SimpleDateFormat("dd-MMM-yyyy"); fmt.setCalendar(calendar); String dateFormatted = fmt.format(calendar.getTime()); return dateFormatted;}
另请注意,月份从0开始,因此您可能的意思是:
int month = Integer.parseInt(splitDate[1]) - 1;
Android SimpleDateFormat,如何使用?
我试图SimpleDateFormat
像这样使用Android :
String _Date = "2010-09-29 08:45:22"
SimpleDateFormat fmt = new SimpleDateFormat("yyyy-MM-dd");
try {
Date date = fmt.parse(_Date);
return fmt.format(date);
}
catch(ParseException pe) {
return "Date";
}
结果很好,我有:2010-09-29
但是如果我更改SimpleDateFormat
为
SimpleDateFormat("dd-MM-yyyy");
问题是我会得到03-03-0035 !!!!
为什么以及如何获取格式dd-MM-yyyy
?
Calendar TimeZone SimpleDateFormat
关于Calendar类的使用可参考:Java Calendar类的使用总结
获取日历(Calendar):java.util.Calendar#getInstance()
获取时区TimeZone:
TimeZone.getTimeZone("GMT+00:00"); 或:TimeZone.getTimeZone("UTC"); TimeZone.getTimeZone("GMT+08:00"); 或:TimeZone.getTimeZone("CTT"); 或:TimeZone.getTimeZone("Asia/Shanghai");
ZoneID可参考:java.time.ZoneId#SHORT_IDS
default TimeZone设定:
1、java.util.TimeZone#setDefault(TimeZone zone)
2、VM options:-Duser.timezone=UTC
语言环境Locale:java.util.Locale#SIMPLIFIED_CHINESE(中国大陆)
Calendar calendar = Calendar.getInstance(); Calendar calendar = Calendar.getInstance("UTC"); Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("GMT+08:00")); Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("Asia/Shanghai")); Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("CTT")); Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("CTT"), Locale.SIMPLIFIED_CHINESE); calendar.set(Calendar.YEAR, 2099); calendar.get(Calendar.HOUR_OF_DAY); //可以获取传入TimeZone对应的时间 calendar.getTime(); //获取的依然是defaultTimeZone对应的时间
java.util.Calendar#getTime 源码: public final Date getTime() { return new Date(getTimeInMillis()); } 因此,通过calendar.getTime()获取的依然是defaultTimeZone对应的时间
SimpleDateFormat转变时区:
DateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); format.setTimeZone(TimeZone.getTimeZone("CTT")); format.format(new Date()); format.format(calendar.getTime());
DateTimeFormatter与SimpleDateFormat
日期格式化类:DateTimeFormatter与SimpleDateFormat
一、SimpleDateFormat类
- SimpleDateFormat是用于以对语言环境敏感的方式格式化和解析日期的具体类。
- SimpleDateFormat类的构造方法
NO | 构造器 | 描述 |
---|---|---|
1 | SimpleDateFormat() | SimpleDateFormat使用默认FORMAT语言环境的默认模式和日期格式符号 构造一个。 |
2 | SimpleDateFormat(Stringpattern) | SimpleDateFormat使用给定的模式和默认FORMAT语言环境的默认日期格式符号 构造一个。 |
3 | SimpleDateFormat(Stringpattern,DateFormatSymbolsformatSymbols) | SimpleDateFormat使用给定的模式和日期格式符号构造一个。 |
4 | SimpleDateFormat(Stringpattern,Localelocale) | SimpleDateFormat使用给定语言环境和给定语言环境的默认日期格式符号构造一个。 |
SimpleDateFormat为什么不是线程安全的?
- SimpleDateFormat类的方法没有使用synchronized来给共享变量加锁。
- SimpleDateFormat继承于DateFormat,下面我们看看我们用来格式化的format()方法的部分源码
- DateFormat.java
public final String format(Date date)
{
return format(date, new StringBuffer(),
DontCareFieldPosition.INSTANCE).toString();
}
public abstract StringBuffer format(Date date, StringBuffer toAppendTo,
FieldPosition fieldPosition);
- SimpleDateFormat.java
@Override
public StringBuffer format(Date date, StringBuffer toAppendTo,
FieldPosition pos)
{
// 如此轻易地使用内部变量,肯定不能线程安全
// 线程都对pos进行写操作,必然会影响其他线程的读操作
pos.beginIndex = pos.endIndex = 0;
return format(date, toAppendTo, pos.getFieldDelegate());
}
private StringBuffer format(Date date, StringBuffer toAppendTo,
FieldDelegate delegate) {
// Convert input date to time field list
// 这里已经彻底毁坏线程的安全性
calendar.setTime(date);
boolean useDateFormatSymbols = useDateFormatSymbols();
for (int i = 0; i < compiledPattern.length; ) {
int tag = compiledPattern[i] >>> 8;
int count = compiledPattern[i++] & 0xff;
if (count == 255) {
count = compiledPattern[i++] << 16;
count |= compiledPattern[i++];
}
switch (tag) {
case TAG_QUOTE_ASCII_CHAR:
toAppendTo.append((char)count);
break;
case TAG_QUOTE_CHARS:
toAppendTo.append(compiledPattern, i, count);
i += count;
break;
default:
subFormat(tag, count, delegate, toAppendTo, useDateFormatSymbols);
break;
}
}
return toAppendTo;
}
看源码不用全部看,只需要看重点,不然你会很难受,很耗费时间。SimpleDateFormat类中的format方法的一段代码calendar.setTime(date);
,从这我们可以看出来,如果我们把SimpleDateFormat定义成static成员变量,那么多个thread之间会共享这个SimpleDateFormat对象, 所以Calendar对象也会被共享。那么当有线程A,B操作该方法时,A线程已经给Calendar对象setTime了,但是这时A线程让出了cpu被B线程抢占了,这时B线程在给Calendar对象setTime一个值,然后A线程获得cpu处理,这时A线程以为使用的是它给setTime的值,其实这里的值已经被B线程更改了。这里就会出现线程不安全,因为这里的处理对象都被两个或者更多的线程公用,就会出现线程不安全,所以我们在开发时,尽量使用内部变量,不共享的变量。 3. 实例
package www.com.lining.dateformate;
import java.text.SimpleDateFormat;
import java.util.Locale;
public class DateTimeFormateTest1 {
private static SimpleDateFormat sdf = new SimpleDateFormat("dd-MMM-yyyy", Locale.US);
private static String date[] = { "01-Jan-1999", "09-Jan-2000", "08-Jan-2001", "07-Jan-2002", "06-Jan-2003",
"05-Jan-2004", "04-Jan-2005", "03-Jan-2006", "02-Jan-2007" };
public static void main(String[] args) {
for (int i = 0; i < date.length; i++) {
final int temp = i;
new Thread(new Runnable() {
@Override
public void run() {
try {
while (true) {
String str1 = date[temp];
String str2 = sdf.format(sdf.parse(str1));
System.out.println(Thread.currentThread().getName() + ", " + str1 + "," + str2);
if (!str1.equals(str2)) {
throw new RuntimeException(
Thread.currentThread().getName() + ", Expected " + str1 + " but got " + str2);
}
}
} catch (Exception e) {
throw new RuntimeException("parse failed", e);
}
}
}).start();
}
}
}
- 输出
- 一定要注意cpu的使用权都是需要去抢占的,所以就会出现多线程情况下,出现线程安全问题。
SimpleDateFormat线程不安全的解决方法
- 将SimpleDateFormat定义成局部变量,每次使用时在new 对象。但是每调用一次方法就会创建一个SimpleDateFormat对象,方法结束又要作为垃圾回收,很浪费资源。
- 加一把线程同步锁:synchronized(lock)
public class SyncDateFormatTest {
private static SimpleDateFormat sdf = new SimpleDateFormat("dd-MMM-yyyy", Locale.US);
private static String date[] = { "01-Jan-1999", "01-Jan-2000", "01-Jan-2001" };
public static void main(String[] args) {
for (int i = 0; i < date.length; i++) {
final int temp = i;
new Thread(new Runnable() {
@Override
public void run() {
try {
while (true) {
synchronized (sdf) {
String str1 = date[temp];
Date date = sdf.parse(str1);
String str2 = sdf.format(date);
System.out.println(Thread.currentThread().getName() + ", " + str1 + "," + str2);
if(!str1.equals(str2)){
throw new RuntimeException(Thread.currentThread().getName()
+ ", Expected " + str1 + " but got " + str2);
}
}
}
} catch (Exception e) {
throw new RuntimeException("parse failed", e);
}
}
}).start();
}
}
}
缺点是:每次都要等该锁释放其他的线程才能使用,性能差。 3. 使用ThreadLocal类
- 直接继承与Object类,该类提供了线程局部变量,这些变量不同于他们的普通对应物,因为访问某个变量的每个线程都有自己的局部变量,它独立于变量的初始化副本。
- 每个线程都将拥有自己的SimpleDateFormat对象副本。
public class DateUtil {
private static ThreadLocal<SimpleDateFormat> local = new ThreadLocal<SimpleDateFormat>();
public static Date parse(String str) throws Exception {
SimpleDateFormat sdf = local.get();
if (sdf == null) {
sdf = new SimpleDateFormat("dd-MMM-yyyy", Locale.US);
local.set(sdf);
}
return sdf.parse(str);
}
public static String format(Date date) throws Exception {
SimpleDateFormat sdf = local.get();
if (sdf == null) {
sdf = new SimpleDateFormat("dd-MMM-yyyy", Locale.US);
local.set(sdf);
}
return sdf.format(date);
}
}
public class ThreadLocalDateFormatTest {
private static String date[] = { "01-Jan-1999", "01-Jan-2000", "01-Jan-2001" };
public static void main(String[] args) {
for (int i = 0; i < date.length; i++) {
final int temp = i;
new Thread(new Runnable() {
@Override
public void run() {
try {
while (true) {
String str1 = date[temp];
Date date = DateUtil.parse(str1);
String str2 = DateUtil.format(date);
System.out.println(str1 + "," + str2);
if(!str1.equals(str2)){
throw new RuntimeException(Thread.currentThread().getName()
+ ", Expected " + str1 + " but got " + str2);
}
}
} catch (Exception e) {
throw new RuntimeException("parse failed", e);
}
}
}).start();
}
}
}
这样每个线程都有自己的副本对象SimpleDateFormat,所以每次不同的线程调用的都是自己的副本对象,不会改变其他线程的对象的。
二、DateTimeFormatter类
- jdk1.8中新增了 LocalDate 与 LocalDateTime等类来解决日期处理方法,同时引入了一个新的类DateTimeFormatter来解决日期格式化问题。
- LocalDateTime,DateTimeFormatter两个类都没有线程问题,只要你自己不把它们创建为共享变量就没有线程问题。
- 可以使用Instant代替 Date,LocalDateTime代替 Calendar,DateTimeFormatter 代替 SimpleDateFormat。
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy MM dd");
LocalDate date = LocalDate.parse("2017 06 17", formatter);
System.out.println(formatter.format(date));
- DateTimeFormatter.ofPattern(pattern)的实现
public static DateTimeFormatter ofPattern(String pattern) {
return new DateTimeFormatterBuilder().appendPattern(pattern).toFormatter();
}
public final class DateTimeFormatterBuilder extends Object
- TimeFormatterBuilder():用于创建日期时间格式化程序的生成器。
- TimeFormatterBuilder().appendPattern(pattern):将指定模式定义的元素追加到构建器,返回TimeFormatterBuilder对象。
- toFormatter():通过DateTimeFormatter使用默认语言环境创建来完成此构建器,获取DateTimeFormatter对象。
- 模式基于字母和符号的简单序列。模式用于使用ofPattern(String)和ofPattern(String, Locale)方法创建格式化程序 。例如, "d MMM uuuu"将2011-12-03的格式设置为“ 2011年12月3日”。从模式创建的格式化程序可以根据需要多次使用,它是不可变的并且是线程安全的。 例如:
LocalDate日期= LocalDate.now();
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(“ yyyy MM dd”);
字符串文本= date.format(formatter);
LocalDate parsedDate = LocalDate.parse(text,formatter);
- 其中的LocalDate和LocalDateTime都可以去查看jdk1.8往上的版本api去学习。
DateTimeFormatter和SimpleDateFormat有什么区别?
DateTimeFormatter和SimpleDateFormat都是用于日期时间格式化和解析的类,但它们有以下几个区别:
1.线程安全性:
- DateTimeFormatter 是线程安全的,可以在多线程环境下共享和重用。
- SimpleDateFormat 不是线程安全的,不建议在多线程环境中共享和重用,除非使用适当的同步措施。
2.API 设计:
- DateTimeFormatter 是 Java 8 中引入的,并遵循了新的日期时间 API 的设计原则,提供了一致且易于使用的方法,支持更多的日期时间模式符号和灵活的格式化选项。
- SimpleDateFormat 是早期的 Java 日期时间 API(java.util.Date) 中的类,使用较老的设计风格,并且其 API 比较有限。
3.底层实现:
- DateTimeFormatter 使用基于解析器和格式化器的模型,底层使用 java.time.format.DateTimeFormatterBuilder 类来构建格式化模式。
- SimpleDateFormat 使用基于模式字符串的方式进行格式化和解析,底层使用 java.text.SimpleDateFormat 类。
以下是使用DateTimeFormatter和SimpleDateFormat的代码示例:
使用DateTimeFormatter示例代码:
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
public class DateTimeFormatterExample {
public static void main(String[] args) {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
// 格式化日期时间
LocalDateTime now = LocalDateTime.now();
String formattedDateTime = formatter.format(now);
System.out.println("格式化后的日期时间:" + formattedDateTime);
// 解析日期时间
String dateTimeString = "2023-07-03 12:30:45";
LocalDateTime parsedDateTime = LocalDateTime.parse(dateTimeString, formatter);
System.out.println("解析后的日期时间:" + parsedDateTime);
}
}
打印结果:
格式化后的日期时间:2023-07-03 15:34:58
解析后的日期时间:2023-07-03T12:30:45
使用SimpleDateFormat示例代码:
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class SimpleDateFormatExample {
public static void main(String[] args) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
// 格式化日期时间
Date now = new Date();
String formattedDateTime = sdf.format(now);
System.out.println("格式化后的日期时间:" + formattedDateTime);
// 解析日期时间
String dateTimeString = "2023-07-03 12:30:45";
try {
Date parsedDateTime = sdf.parse(dateTimeString);
System.out.println("解析后的日期时间:" + parsedDateTime);
} catch (ParseException e) {
e.printStackTrace();
}
}
}
打印结果:
格式化后的日期时间:2023-07-03 15:38:33
解析后的日期时间:Mon Jul 03 12:30:45 CST 2023
在这个示例中,我们分别使用了DateTimeFormatter和SimpleDateFormat来格式化和解析日期时间。它们的用法非常相似,但是需要注意的是,DateTimeFormatter是线程安全的,可以在多线程环境下共享和重用;而SimpleDateFormat不是线程安全的,不建议在多线程环境中共享和重用。
今天关于将GregorianCalendar与SimpleDateFormat一起使用的讲解已经结束,谢谢您的阅读,如果想了解更多关于Android SimpleDateFormat,如何使用?、Calendar TimeZone SimpleDateFormat、DateTimeFormatter与SimpleDateFormat、DateTimeFormatter和SimpleDateFormat有什么区别?的相关知识,请在本站搜索。
本文标签: