Java中的时间和日期(上)

 

自从JDK 1.0开始,Java就提供了Date来处理时间和日期,作为老古董自然有很多东西是过时的。然后出现了Calendar来解决了很多问题,但是Calendar使用比较复杂,并且有些反人类的地方。直到Java 8的出现,它吸收了Joda-Time库的经验,使得Java处理时间和日期变得比较”人性化”了。

本篇就来谈谈Java中的Date、Calendar,以及SimpleDateFormat的使用。在Java中的时间和日期(下)里面再对比一下Java 8中的日期处理。

1. 古老的 java.util.Date

查看一下Date类的源码,可以看到6个构造方法中,有4个已经添加了@Deprecated的标签了,剩下没过时的只有两个:

public Date() {
    this(System.currentTimeMillis());
}

public Date(long var1) {
    this.fastTime = var1;
}

其中,第一个构造方法调用的是System.currentTimeMillis()方法,这个方法返回的是一个long整数,表示GMT 1970年1月1日 00:00:00到现在所经历的毫秒数。这个毫秒数我们暂且称之为milliseconds值,这个值很重要,无论是在Date类中还是Calendar类中,milliseconds值都是计算时间日期的基准。

怎么获得这个长整型的数呢?需要调用getTime()方法,注意并不是调用toString()方法,它们两者的差异可以重下面的代码中体现出来:

public static void main(String[] args) {
    Date date = new Date();
    System.out.println(date.getTime());     // 1467628171312
    System.out.println(date.toString());    // Mon Jul 04 18:29:31 CST 2016
}

而第二个构造方法的参数,表示创建的Date对象与GMT 1970年1月1日 00:00:00的时间差。比如,3600 * 1000毫秒是一小时,那么我们用getTime()来验证一下:

public static void main(String[] args) {
    Date date = new Date(3600 * 1000);
    System.out.println(date.getTime());     // 3600000
}

没问题,然后我们调用一下toString()方法,看看返回的是什么:

public static void main(String[] args) {
    Date date = new Date(3600 * 1000);
    System.out.println(date.toString());     // Thu Jan 01 09:00:00 CST 1970
}

嗯?竟然是9点,为什么不是1点呢?怎么差了8个小时?有此疑问的童鞋都是看书不仔细的。而看书仔细的童鞋则会问“CST和GMT是什么关系”之类的。因为CST是指的北京时间(China Standard Time),而GMT是指的是格林尼治标准时间(Greenwich Mean Time)。由于北京处于东八区,比GMT早8小时,所以打印的时间指的是北京时间1970年1月1日上午9点。

谈完了构造方法,下面说说Date这个古老的类中可以使用的方法。

    • booleanafter(Date when)

      测试此日期是否在指定日期之后。

      booleanbefore(Date when)

      测试此日期是否在指定日期之前。

      Objectclone()

      返回此对象的副本。

      intcompareTo(Date anotherDate)

      比较两个日期进行订购。

      booleanequals(Object obj)

      比较两个日期来平等。

      static Datefrom(Instant instant)

      Instant对象获取一个 Date的实例。

    • longgetTime()

      返回自1970年1月1日以来,由此 Date对象表示的00:00:00 GMT的毫秒 数 。

一段代码解释上面的方法:

public static void main(String[] args) {
    Date nowaday = new Date();
    System.out.println(nowaday.getTime());      // 1467633231471
    System.out.println(nowaday.toString());     // Mon Jul 04 19:53:51 CST 2016

    Date date = new Date(3600 * 1000);
    System.out.println(nowaday.before(date));   // false
    System.out.println(nowaday.after(date));    // true

    nowaday.setTime(3600 * 1000);
    System.out.println(nowaday);                // Thu Jan 01 09:00:00 CST 1970
}

Date类中的构造方法和常用的未过时的方法基本就是这些了。看了之后是不是觉得其实Date类能用的东西很少?很多日期的操作,比如获取年月日啊,取这周周一的日期啊什么的都很难实现,这时候就要使用到Calendar类,或者使用更牛逼的Java 8中的时间日期包。

 

2. 庞大的 java.util.Calendar

Calendar类的构造方法

与Date类不同,Calendar 类是一个抽象类。其直接子类是 GregorianCalendar既然Calendar类是抽象类,那么如获取Calendar对象呢?可以使用下面的代码来创建一个Calendar对象:

Calendar rightNow = Calendar.getInstance();

和Date一样,创建好对象之后,便包含了当前日期和时间的信息。

其实,getInstance()这个静态方法还有三个重载方法,在源码中我们可以看到它们4个欢聚一堂的情景:

public static synchronized Calendar getInstance() {
    return new GregorianCalendar();
}
public static synchronized Calendar getInstance(Locale locale) {
    return new GregorianCalendar(locale);
}
public static synchronized Calendar getInstance(TimeZone timezone) {
    return new GregorianCalendar(timezone);
}
public static synchronized Calendar getInstance(TimeZone timezone, Locale locale) {
    return new GregorianCalendar(timezone, locale);
}

估计大家都能看出来,这4个重载方法的区别在于时区和地区的不同。而它们都是通过创建子类(GregorianCalendar)的对象来返回一个Calendar对象,这其实是多态的一种应用,也是设计模式中工厂模式的应用。也就是说,我们也可以像下面那样来创建一个Calendar对象:

Calendar myCalendar = new GregorianCalendar();

关于时区和地区这里不做详细的介绍,只展示一下其用法:

public static void main(String[] args) {
    TimeZone timeZone = TimeZone.getTimeZone("GMT");
    Locale locale = Locale.CHINA;
    Calendar calendar = Calendar.getInstance(timeZone, locale);
}

Calendar的常用方法

get()和set()方法

Date对象可以通过getTime()方法返回 Long 类型 和toString()方法,能很容易的取到对应的时间信息。

Calendar对象中,getTime()方法返回的是一个Date对象,getTimeInMillis()方法返回 Long 类型,至于toString()方法返回的东西嘛,你们感受一下

java.util.GregorianCalendar[  
   time=1467638240540,
   areFieldsSet=true,
   areAllFieldsSet=true,
   lenient=true,
   zone=sun.util.calendar.ZoneInfo   [  
      id="Asia/Shanghai",
      offset=28800000,
      dstSavings=0,
      useDaylight=false,
      transitions=19,
      lastRule=null
   ],
   firstDayOfWeek=1,
   minimalDaysInFirstWeek=1,
   ERA=1,
   YEAR=2016,
   MONTH=6,
   WEEK_OF_YEAR=28,
   WEEK_OF_MONTH=2,
   DAY_OF_MONTH=4,
   DAY_OF_YEAR=186,
   DAY_OF_WEEK=2,
   DAY_OF_WEEK_IN_MONTH=1,
   AM_PM=1,
   HOUR=9,
   HOUR_OF_DAY=21,
   MINUTE=17,
   SECOND=20,
   MILLISECOND=540,
   ZONE_OFFSET=28800000,
   DST_OFFSET=0
]

虽然这从侧面反映了Calendar比Date强大,能提供更多的信息,不过估计你们轻易不会使用Calendar的toString()方法的吧?其实在Calendar类中,有一点和Date类是一样的:它们都会保存一个milliseconds的值。Calendar类对于时间日期的各种计算都是基于这个值来的。你看toString()方法返回的第一个值就是它,足以说明这个值的重要性。

要获取Calendar对象所提供的信息,需要调用get()方法。在源码中,get()方法做了如下的事情:

public int get(int field) {
    complete();
    return fields[field];
}

complete()方法中,会调用computeTime()computeFields()方法,这两个方法都是抽象方法,由子类GregorianCalendar实现。在computeTime()方法中,计算出年月日时分秒等等时间相关的信息,而在computeFields()方法中获取到对应的时区地区等信息。这两个方法会将所计算出来的信息保存在一个int类型的数组中,这个数组的名字,没错,就是fields。fields数组保存的信息如下所示:

public static final int ERA = 0;
public static final int YEAR = 1;
public static final int MONTH = 2;
public static final int WEEK_OF_YEAR = 3;
public static final int WEEK_OF_MONTH = 4;
public static final int DATE = 5;
public static final int DAY_OF_MONTH = 5;
public static final int DAY_OF_YEAR = 6;
public static final int DAY_OF_WEEK = 7;
public static final int DAY_OF_WEEK_IN_MONTH = 8;
public static final int AM_PM = 9;
public static final int HOUR = 10;
public static final int HOUR_OF_DAY = 11;
public static final int MINUTE = 12;
public static final int SECOND = 13;
public static final int MILLISECOND = 14;
public static final int ZONE_OFFSET = 15;
public static final int DST_OFFSET = 16;

嗯,一共18个常量(注意第6个和第7个的值是一样的)。也就是说,get()方法中你可以传入的参数就是上述18个常量之一。你既可以传常量名(如YEAR等),也可以传数字进去(如1)。当然为了可读性,一般都传入常量名。其中有几个参数可能需要解释一下:

  • ERA 
    表示该日期是在公元纪年(公元0年)之前还是之后,如果返回0表示在公元纪年之前,返回1表示在公元纪年之后。
  • AM_PM 
    表示该时间是在中午12点之前还是之后,如果返回0表示在中午12点之前,返回1表示在中午12点之后。
  • DST_OFFSET 
    表示该时间距夏令时的毫秒数。

下面就举个简单的例子来说明一下吧:

public static void main(String[] args) {
    Calendar calendar = Calendar.getInstance();
    System.out.println(calendar.get(Calendar.YEAR));            // 2016
    System.out.println(calendar.get(Calendar.MONTH));           // 6
    System.out.println(calendar.get(Calendar.DAY_OF_MONTH));    // 6
    System.out.println(calendar.get(Calendar.ERA));             // 1
}

有一点要注意的是,由于Calendar类中的常量比较多,你可能传入的常量名不是上述18个之一,那么就可能发生一些意想不到的结果,比如,在get()方法中如果我们传入一个月份,这么写:

public static void main(String[] args) {
    Calendar calendar = Calendar.getInstance();
    System.out.println(calendar.get(Calendar.DECEMBER));    // 22
}

返回的22是什么鬼?其实是因为Calendar.DECEMBER的值是11,它返回的其实是HOUR_OF_DAY的返回值,也就是22点钟。用代码解释就是下面那样:

public static void main(String[] args) {
    Calendar calendar = Calendar.getInstance();
    System.out.println(calendar.getTime().toString());      // Mon Jul 04 22:24:08 CST 2016
    System.out.println(calendar.get(Calendar.HOUR_OF_DAY)); // 22
    System.out.println(calendar.get(Calendar.DECEMBER));    // 22
}

如果你不小心在Calendar.get()方法中传入了类似Calendar.DECEMBER)的参数,那么编译器会发出警告,这时候你就可以看看是不是弄错了。当然,如果你对警告置之不理,那只能后果自负。

谈完了get()方法,该说说set()方法了。get()方法是获取时间信息,那么set()方法则是对当前的calendar对象设置时间和日期。那么我们看看set()方法有那些重载的方法:

public void set(int field, int value) {
    fields[field] = value;
    isSet[field] = true;
    areFieldsSet = isTimeSet = false;
    if (field > MONTH && field < AM_PM) {
        lastDateFieldSet = field;
    }
    if (field == HOUR || field == HOUR_OF_DAY) {
        lastTimeFieldSet = field;
    }
    if (field == AM_PM) {
        lastTimeFieldSet = HOUR;
    }
}
public final void set(int year, int month, int day) {
    set(YEAR, year);
    set(MONTH, month);
    set(DATE, day);
}
public final void set(int year, int month, int day, int hourOfDay, int minute) {
    set(year, month, day);
    set(HOUR_OF_DAY, hourOfDay);
    set(MINUTE, minute);
}
public final void set(int year, int month, int day, int hourOfDay, int minute, int second) {
    set(year, month, day, hourOfDay, minute);
    set(SECOND, second);
}

很简单,就是将我们传入的值存放到fields数组中。调用set()方法会改变当前Calendar对象的时间和日期。下面用一段简单的代码说明用法:

public static void main(String[] args) {
    Calendar calendar = Calendar.getInstance();

    calendar.set(Calendar.MONTH, 5);
    System.out.println(calendar.get(Calendar.MONTH));           // 5

    calendar.set(2016, Calendar.JANUARY, 2);
    System.out.println(calendar.get(Calendar.YEAR));            // 2016
    System.out.println(calendar.get(Calendar.MONTH));           // 0
    System.out.println(calendar.get(Calendar.DAY_OF_MONTH));    // 2

}

add()和roll()方法

使用get()和set()方法可以获取当前时间和日期,也可以设置Calendar对象的时间和日期。但是一些简单的时间日期的计算我们仍然无法快速获得。比如昨天的日期?这时,就需要使用到add()和roll()方法了。

add(int field, int value)方法接受两个参数,第一个参数表示你想改变的字段,这个字段是fields数组中的一个。第二个参数是改变的值。下面用代码看看效果:

public static void main(String[] args) {
    Calendar calendar = Calendar.getInstance();

    System.out.println(calendar.getTime().toString());  // Wed Jul 06 10:41:10 CST 2016
    calendar.add(Calendar.MONTH, 2);
    System.out.println(calendar.get(Calendar.MONTH));   // 8

    calendar.set(Calendar.MONTH, 9);
    System.out.println(calendar.get(Calendar.MONTH));   // 9
    calendar.add(Calendar.MONTH, 4);
    System.out.println(calendar.get(Calendar.MONTH));   // 1

    calendar.set(2016, Calendar.FEBRUARY, 28);
    calendar.add(Calendar.DAY_OF_MONTH, 3);
    System.out.println(calendar.getTime().toString());  //Wed Mar 02 13:18:02 CST 2016

    calendar.set(2016, Calendar.JANUARY, 2);
    calendar.add(Calendar.DAY_OF_MONTH, -3);
    System.out.println(calendar.getTime().toString());  // Wed Dec 30 13:18:02 CST 2015
}

上面这段代码看懂了吗?第4行代码打印了当前时间,当前是7月,第5行代码将月份增加了2个月,第6行代码打印了增加之后的月份,嗯?八月?其实不是的。由于在Calendar中月份计数是从0开始的,一月是0,那么8代表的就是九月。同理,第8行将月份设置的是10月,将月份增加4个月后,就是第二年的2月,也就是返回的1。

第14行代码,将二月份的日期加三天,则变成了三月二日(2016年2月有29天)。第18行代码,将1月2日减三天,变成了上一年的12月30日。

由于月份是从0开始计算的,所以计算月份的时候需要特别小心。这就是Calendar反人类的地方之一。

总结一下,使用add()方法有几点需要注意的:

  • 月份是从0开始计数的。
  • add()方法的第二个参数如果为正,则数据增加;如果为负,则数据减少。
  • 当增加的数目超过法定额度时,会自动向更高一级的单位加1。反之亦然。

然后我们再来看看roll()方法。将上面的代码中的add()方法全部替换为roll()方法,结果如下:

public static void main(String[] args) {
    Calendar calendar = Calendar.getInstance();

    System.out.println(calendar.getTime().toString());  // Wed Jul 06 13:24:10 CST 2016
    calendar.roll(Calendar.MONTH, 2);
    System.out.println(calendar.get(Calendar.MONTH));   // 8

    calendar.set(Calendar.MONTH, 9);
    System.out.println(calendar.get(Calendar.MONTH));   // 9
    calendar.roll(Calendar.MONTH, 4);
    System.out.println(calendar.get(Calendar.MONTH));   // 1

    calendar.set(2016, Calendar.FEBRUARY, 28);
    calendar.roll(Calendar.DAY_OF_MONTH, 3);
    System.out.println(calendar.getTime().toString());  // Tue Feb 02 13:24:10 CST 2016

    calendar.set(2016, Calendar.JANUARY, 2);
    calendar.roll(Calendar.DAY_OF_MONTH, -3);
    System.out.println(calendar.getTime().toString());  // Sat Jan 30 13:24:10 CST 2016
}

前面的没问题,和add()效果时一样的,后面涉及到进位和退位的时候,就和add()方法表现得不一样了。在roll()方法中不会进行进位和退位运算这一点是和add()方法最主要的区别。

其它几个有趣的方法

上面介绍的4个方法,set(),get(),add(),roll()是日常使用频率比较高的。但是有几个方法,其实还是比较有趣的,在特定的场合能减少你的代码量。

1.getMaximum(int field)getMinimum(int field) 
这两个方法,返回Calendar对象的fields数组中对应数据的最大值和最小值。也就是说,如果我想知道Calendar.DAY_OF_MONTH这个字段能取到的最大值是多少,就可以使用calendar.getMaximum(Calendar.DAY_OF_MONTH)来获取,返回的值是31,因为一个月最多可以有31天。

2.getActualMaximum(int field)getActualMinimum(int field) 
这两个方法名字同上面两个方法相比,多了一个Actual单词,表示返回Calendar对象的fields数组中,在当前日期的环境条件下,对应数据的最大值和最小值。也就是说,如果Calendar对象表示的是2016年的2月,那么使用calendar.getActualMaximum(Calendar.DAY_OF_MONTH)返回的就是29,因为2016年的2月最多只有29天。

上面的方法,用代码解释如下:

public static void main(String[] args) {
    Calendar calendar = Calendar.getInstance();
    System.out.println(calendar.getMaximum(Calendar.MONTH));              // 11
    System.out.println(calendar.getMinimum(Calendar.HOUR_OF_DAY));        // 0
    System.out.println(calendar.getActualMaximum(Calendar.DATE));         // 31
    System.out.println(calendar.getActualMinimum(Calendar.DATE));         // 1
}

这几个方法有什么用呢?比如需要让用户输入本月的一个日期的话,就可以使用getActualMaximum(int field)方法来进行输入验证,判断用户输入的日期是否合法。

那么fields数组中的各个字段的最大值和最小值分别是多少呢?下面是从源码中找出来的,自己可以对照着上面的fields数组字段名称欣赏一下。

private static int[] maximums = new int[] { 1, 292278994, 11, 53, 6, 31,
        366, 7, 6, 1, 11, 23, 59, 59, 999, 14 * 3600 * 1000, 7200000 };

private static int[] minimums = new int[] { 0, 1, 0, 1, 0, 1, 1, 1, 1, 0,
        0, 0, 0, 0, 0, -13 * 3600 * 1000, 0 };

Calendar和Date类的关系

做为对Date类的补充和替代,当然得和Date进行相互转化。

1.使用getTime()方法,从Calendar对象中获取Date对象。

public static void main(String[] args) {
    Calendar calendar = Calendar.getInstance();
    Date date = calendar.getTime();
    System.out.println(date.toString());            // Mon Jul 04 21:08:27 CST 2016
}

2.使用setTime()方法,将Date对象得值赋值给Calendar对象。

public static void main(String[] args) {
    Calendar calendar = Calendar.getInstance();
    System.out.println(calendar.getTimeInMillis());     // 1467637991365

    Date date = new Date(3600 * 1000);
    calendar.setTime(date);
    System.out.println(calendar.getTimeInMillis());     // 3600000
}

还记得介绍Date类时说过,Date的构造方法中,有4个构造方法已经过时了。其实它们是被Calendar类的相关方法给替代了。比如:

  • Date(int year, int month, int date) 
    Calendar.set(year + 1900, month, date)代替。
  • Date(int year, int month, int date, int hrs, int min) 
    Calendar.set(year + 1900, month, date, hrs, min)代替
  • Date(int year, int month, int date, int hrs, int min, int sec) 
    Calendar.set(year + 1900, month, date, hrs, min, sec)代替
  • Date(String s) 
    DateFormat.parse(String s)代替

 

3. java.text.SimpleDateFormat 格式化日期和时间

有了Date和Calendar,我们能获取和设置时间和日期,还可以使用SimpleDateFormat这个类来 格式化日期和时间,返回的字符串就是格式化后的结果

比如想要获得当前时间,输出是哪年哪月几号星期几,几时几分几秒,就可以用下面的代码来实现:

public static void main(String[] args) {
    Calendar calendar = Calendar.getInstance();
		
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    String dateStr = sdf.format(System.currentTimeMillis());
    System.out.println(dateStr);    //2018-07-21 15:36:55

    String dateStr2 = sdf.format(calendar.getTimeInMillis());
    System.out.println(dateStr2);   //2018-07-21 15:36:55
}

先看一下构造方法,SimpleDateFormat类的构造方法有四个,分别是:

  • SimpleDateFormat()
  • SimpleDateFormat(String pattern)
  • SimpleDateFormat(String pattern, DateFormatSymbols formatSymbols)
  • SimpleDateFormat(String pattern, Locale locale)

如果SimpleDateFormat使用的是空参数构造方法,那需要调用applyPattern(String pattern)方法来将pattern传入

SimpleDateFormat sdf = new SimpleDateFormat();
String pattern = "2018-07-21 15:36:55";
sdf.applyPattern(pattern);
		
String dateStr = sdf.format(System.currentTimeMillis());
System.out.println(dateStr);

// 与上面一段代码的效果相同
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String dateStr = sdf.format(System.currentTimeMillis());

得到了pattern参数后,SimpleDateFormat对象就具有了格式化日期的能力了,这时只需要调用format()方法,将Date对象传入该方法中,返回的字符串就是格式化后的结果

pattern参数 官网API文档。

LetterDate or Time ComponentPresentationExamples
GEra designatorTextAD
yYearYear1996; 96
YWeek yearYear2009; 09
MMonth in year (context sensitive)MonthJuly; Jul; 07
LMonth in year (standalone form)MonthJuly; Jul; 07
wWeek in yearNumber27
WWeek in monthNumber2
DDay in yearNumber189
dDay in monthNumber10
FDay of week in monthNumber2
EDay name in weekTextTuesday; Tue
uDay number of week (1 = Monday, …, 7 = Sunday)Number1
aAm/pm markerTextPM
HHour in day (0-23)Number0
kHour in day (1-24)Number24
KHour in am/pm (0-11)Number0
hHour in am/pm (1-12)Number12
mMinute in hourNumber30
sSecond in minuteNumber55
SMillisecondNumber978
zTime zoneGeneral time zonePacific Standard Time; PST; GMT-08:00
ZTime zoneRFC 822 time zone-0800
XTime zoneISO 8601 time zone-08; -0800; -08:00

注意区分大小写

 

SimpleDateFormat类除了能将Date对象进行格式化返回字符串,也可以使用 parse(String source)将一个日期字符串解析返回成一个Date对象,比如:

public static void main(String[] args) {
    String s = "2016#08#01";
    SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy#MM#dd");
    try {
        Date date = simpleDateFormat.parse(s);
        System.out.println(date.toString());        // Mon Aug 01 00:00:00 CST 2016
        System.out.println(date.getTime());        // 1467637991365
    } catch (ParseException e) {
        e.printStackTrace();
    }
}

嗯,估计大家看出来了,这里需要使用 # 符号来进行分割数据,其他 - 符号也可以 两者一致即可

最后说一点,SimpleDateFormat类不是线程安全的,如果有多个线程需要使用到SimpleDateFormat对象,建议每个线程单独创建,如果多个线程要获取同一个SimpleDateFormat对象,记得要加锁!

格式化与解析转换写了一个DateStringChangeUtils工具类,可以在开发中使用

public class DateStringChangeUtils {
    /**
     *  默认的日期时间模式
     */
    public static final String DEFAULT_DATE_PATTERN = "yyyy-MM-dd HH:mm:ss";
    private DateStringChangeUtils(){}

    /**
     *  默认格式解析操作:将String类型 --> Date类型
     * @param source
     * @return string
     */
    public static Date string2date(String source) throws ParseException {
        return string2date(source,null);
    }

    /**
     *  自定义解析操作:将String类型 --> Date类型
     * @param source
     * @param pattern
     * @return Date
     */
    public static Date  string2date(String source,String pattern) throws ParseException {
        SimpleDateFormat sdf = new SimpleDateFormat();
        if(StringUtils.isBlank(pattern)){
            pattern  = DEFAULT_DATE_PATTERN;
        }
        sdf.applyPattern(pattern);
        return sdf.parse(source);
    }

    /**
     *  默认格式化操作:将Date类型 --> String类型
     * @param date
     * @return string
     */
    public static String date2string(Date date){
        return date2string(date,null);
    }

    /**
     *  自定义格式化操作:将Date类型 --> String类型
     * @param date
     * @param pattern
     * @return string
     */
    public static String date2string(Date date,String pattern){
        SimpleDateFormat sdf = new SimpleDateFormat();
        if(StringUtils.isBlank(pattern)){
            pattern  = DEFAULT_DATE_PATTERN;
        }
        sdf.applyPattern(pattern);
        return sdf.format(date);
    }

    public static void main(String[] args) throws ParseException {
        System.out.println(date2string(new Date()));
        System.out.println(date2string(new Date(),null));
        System.out.println(date2string(new Date(),"yyyy-MM-dd"));
        System.out.println(date2string(new Date(),"yyyy#MM#dd"));

        // 解析 String的格式要和 pattern要一致
        System.out.println(string2date("2018-06-29 11:36:20").toLocaleString());
        System.out.println(string2date("2018-06-29 11:36:20",null).toLocaleString());
        System.out.println(string2date("2018-06-29","yyyy-MM-dd"));
        System.out.println(string2date("2018#06#29","yyyy#MM#dd"));
    }
}

public class StringUtils {
    private StringUtils(){}
    /**
     * 判断字符串为空
     * @param str
     * @return true - 为空,false - 非空
     */
    public static boolean isBlank(String str) {
        return !isNonBlank(str);
    }

    /**
     * 判断字符串为非空
     * @param str
     * @return true - 非空,false - 为空
     */
    public static boolean isNonBlank(String str) {
        if (str != null && !"".equals(str.trim())) {
            return true;
        } else {
            return false;
        }
    }
}

 

时间的比较:转换成 long 类型 比较  ,可以得到日期相差的时间

 

参考文章: https://blog.csdn.net/wl9739/article/details/51839502

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java提供了许多用于处理日期时间的类和方法。其最常用的是: 1. Date类:表示日期时间的类。现在已经被废弃,不建议使用。 2. Calendar类:是一个抽象类,提供了处理日期时间的方法。 3. SimpleDateFormat类:可以将日期时间格式化成指定的字符串。 4. LocalDateTime类:Java 8引入的新类,用于表示日期时间,提供了许多方便的方法。 5. Duration类和Period类:用于表示时间间隔。 下面是一些示例代码: 1. 获取当前日期时间 ```java Date date = new Date(); System.out.println(date); LocalDateTime now = LocalDateTime.now(); System.out.println(now); ``` 2. 格式化日期时间 ```java SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); String formattedDate = sdf.format(date); System.out.println(formattedDate); DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); String formattedNow = now.format(formatter); System.out.println(formattedNow); ``` 3. 计算时间间隔 ```java LocalDateTime start = LocalDateTime.of(2021, 1, 1, 0, 0, 0); LocalDateTime end = LocalDateTime.now(); Duration duration = Duration.between(start, end); System.out.println(duration.toDays()); LocalDate startDate = LocalDate.of(2021, 1, 1); LocalDate endDate = LocalDate.now(); Period period = Period.between(startDate, endDate); System.out.println(period.getYears()); ``` 这里只是简单介绍了一些Java处理日期时间的基础知识,具体的使用方法还需要根据实际需求进行学习和掌握。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值