GVKun编程网logo

将GregorianCalendar与SimpleDateFormat一起使用

22

本篇文章给大家谈谈将GregorianCalendar与SimpleDateFormat一起使用,同时本文还将给你拓展AndroidSimpleDateFormat,如何使用?、CalendarTim

本篇文章给大家谈谈将GregorianCalendar与SimpleDateFormat一起使用,同时本文还将给你拓展Android SimpleDateFormat,如何使用?、Calendar TimeZone SimpleDateFormat、DateTimeFormatter与SimpleDateFormat、DateTimeFormatter和SimpleDateFormat有什么区别?等相关知识,希望对各位有所帮助,不要忘了收藏本站喔。

本文目录一览:

将GregorianCalendar与SimpleDateFormat一起使用

将GregorianCalendar与SimpleDateFormat一起使用

因此,我一直在为这个(应该是)简单的练习而绞尽脑汁,以使该程序将日期字符串转换为GregorianCalendar对象,对其进行格式化,并在完成后将其作为字符串再次返回。

这是程序的最后一点,它从文件中获取一小段文本,将其分解为单独的记录,然后将记录分解为单独的数据并将它们分配给个人对象。

我已经在多个位置检查了该代码,并且该代码完全执行了应该执行的操作,直到调用了format函数(该函数抛出)为止IllegalArgumentException。为GergorianCalendar对象分配了应该分配的值(尽管再次打印,如下所示),但是格式不会接受该对象进行格式化。

不幸的是,讲师不太确定如何使用GregorianCalendarand
SimpleDateFormat(但还是指派我们与他们合作),并说:“只是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是a
GregorianCalendar)。

更新的代码:

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功能链接在一起,而是串联使用它们。首先,将出生日期转换为a
GregorianCalendar并将其存储在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,如何使用?

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 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

日期格式化类:DateTimeFormatter与SimpleDateFormat

一、SimpleDateFormat类

  1. SimpleDateFormat是用于以对语言环境敏感的方式格式化和解析日期的具体类。
  2. SimpleDateFormat类的构造方法
NO 构造器 描述
1 SimpleDateFormat() SimpleDateFormat使用默认FORMAT语言环境的默认模式和日期格式符号 构造一个。
2 SimpleDateFormat​(Stringpattern) SimpleDateFormat使用给定的模式和默认FORMAT语言环境的默认日期格式符号 构造一个。
3 SimpleDateFormat​(Stringpattern,DateFormatSymbolsformatSymbols) SimpleDateFormat使用给定的模式和日期格式符号构造一个。
4 SimpleDateFormat​(Stringpattern,Localelocale) SimpleDateFormat使用给定语言环境和给定语言环境的默认日期格式符号构造一个。
SimpleDateFormat为什么不是线程安全的?
  1. SimpleDateFormat类的方法没有使用synchronized来给共享变量加锁。
  2. 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();
		}
	}
}

  1. 输出
  2. 一定要注意cpu的使用权都是需要去抢占的,所以就会出现多线程情况下,出现线程安全问题。
SimpleDateFormat线程不安全的解决方法
  1. 将SimpleDateFormat定义成局部变量,每次使用时在new 对象。但是每调用一次方法就会创建一个SimpleDateFormat对象,方法结束又要作为垃圾回收,很浪费资源。
  2. 加一把线程同步锁: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类

  1. jdk1.8中新增了 LocalDate 与 LocalDateTime等类来解决日期处理方法,同时引入了一个新的类DateTimeFormatter来解决日期格式化问题。
  2. LocalDateTime,DateTimeFormatter两个类都没有线程问题,只要你自己不把它们创建为共享变量就没有线程问题。
  3. 可以使用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));
  1. 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);
  1. 其中的LocalDate和LocalDateTime都可以去查看jdk1.8往上的版本api去学习。

DateTimeFormatter和SimpleDateFormat有什么区别?

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有什么区别?的相关知识,请在本站搜索。

本文标签: