为什么使用JDK8的时间

好用!
好用!
好用!

高大上,线程安全,计算方便等一些列的好处,你什么不使用它

JDK8时间

编号 类的名称 描述
1 Instant 时间戳
2 Duration 持续时间,时间差
3 LocalDate 只包含日期,比如:2018-02-05
4 LocalTime 只包含时间,比如:23:12:10
5 LocalDateTime 包含日期和时间,比如:2018-02-05 23:14:21
6 Period 时间段
7 ZoneOffset 时区偏移量,比如:+8:00
8 ZonedDateTime 带时区的时间
9 Clock 时钟,比如获取目前美国纽约的时间
10 java.time.format.DateTimeformaer 时间格式化

e.g. 1. Java 8中处理特定日期

我们通过静态工厂方法now()非常容易地创建了当天日期,你还可以调用另一个有用的工厂方法LocalDate.of()创建任意日期, 该方法需要传入年、月、日做参数,返回对应的LocalDate实例。这个方法的好处是没再犯老API的设计错误,比如年度起始于1900,月份是从0开 始等等。


import java.time.LocalDate;

public class Demo03 {
    public static void main(String[] args) {
        LocalDate date = LocalDate.of(2018,2,6);
        System.out.println("自定义日期:"+date);
    }
}

e.g. 2. Java 8中检查像生日这种周期性事件


import java.time.LocalDate;
import java.time.MonthDay;

public class Demo05 {
    public static void main(String[] args) {
        LocalDate date1 = LocalDate.now();

        LocalDate date2 = LocalDate.of(2018,2,6);
        MonthDay birthday = MonthDay.of(date2.getMonth(),date2.getDayOfMonth());
        MonthDay currentMonthDay = MonthDay.from(date1);

        if(currentMonthDay.equals(birthday)){
            System.out.println("是你的生日");
        }else{
            System.out.println("你的生日还没有到");
        }

    }
}

只要当天的日期和生日匹配,无论是哪一年都会打印出祝贺信息。你可以把程序整合进系统时钟,看看生日时是否会受到提醒,或者写一个单元测试来检测代码是否运行正确。

e.g. 3. Java 8的Clock时钟类

Java 8增加了一个Clock时钟类用于获取当时的时间戳,或当前时区下的日期时间信息。以前用到System.currentTimeInMillis()和TimeZone.getDefault()的地方都可用Clock替换。


import java.time.Clock;

public class Demo10 {
    public static void main(String[] args) {
        // Returns the current time based on your system clock and set to UTC.
        Clock clock = Clock.systemUTC();
        System.out.println("Clock : " + clock.millis());

        // Returns time based on system clock zone
        Clock defaultClock = Clock.systemDefaultZone();
        System.out.println("Clock : " + defaultClock.millis());

    }
}

e.g. 4. Java 8中处理时区

Java 8不仅分离了日期和时间,也把时区分离出来了。现在有一系列单独的类如ZoneId来处理特定时区,ZoneDateTime类来表示某时区下的时间。这在Java 8以前都是 GregorianCalendar类来做的。下面这个例子展示了如何把本时区的时间转换成另一个时区的时间。


import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;

public class Demo12 {
    public static void main(String[] args) {
        // Date and time with timezone in Java 8
        ZoneId america = ZoneId.of("America/New_York");
        LocalDateTime localtDateAndTime = LocalDateTime.now();
        ZonedDateTime dateAndTimeInNewYork  = ZonedDateTime.of(localtDateAndTime, america );
        System.out.println("Current date and time in a particular timezone : " + dateAndTimeInNewYork);
    }
}

e.g. 5. 如何表示信用卡到期这类固定日期,答案就在YearMonth

与 MonthDay检查重复事件的例子相似,YearMonth是另一个组合类,用于表示信用卡到期日、FD到期日、期货期权到期日等。还可以用这个类得到 当月共有多少天,YearMonth实例的lengthOfMonth()方法可以返回当月的天数,在判断2月有28天还是29天时非常有用。


import java.time.*;

public class Demo13 {
    public static void main(String[] args) {
        YearMonth currentYearMonth = YearMonth.now();
        System.out.printf("Days in month year %s: %d%n", currentYearMonth, currentYearMonth.lengthOfMonth());
        YearMonth creditCardExpiry = YearMonth.of(2019, Month.FEBRUARY);
        System.out.printf("Your credit card expires on %s %n", creditCardExpiry);
    }
}

e.g. 6. 如何在Java 8中检查闰年


import java.time.LocalDate;

public class Demo14 {
    public static void main(String[] args) {
        LocalDate today = LocalDate.now();
        if(today.isLeapYear()){
            System.out.println("This year is Leap year");
        }else {
            System.out.println("2018 is not a Leap year");
        }

    }
}

e.g. 7. 计算两个日期之间的天数和月数

有一个常见日期操作是计算两个日期之间的天数、周数或月数。在Java 8中可以用java.time.Period类来做计算。

下面这个例子中,我们计算了当天和将来某一天之间的月数。


import java.time.LocalDate;
import java.time.Period;

public class Demo15 {
    public static void main(String[] args) {
        LocalDate today = LocalDate.now();

        LocalDate java8Release = LocalDate.of(2018, 12, 14);

        Period periodToNextJavaRelease = Period.between(today, java8Release);
        System.out.println("Months left between today and Java 8 release : "
                + periodToNextJavaRelease.getMonths() );


    }
}

e.g. 8. 在Java 8中获取当前的时间戳

Instant类有一个静态工厂方法now()会返回当前的时间戳,如下所示:


import java.time.Instant;

public class Demo16 {
    public static void main(String[] args) {
        Instant timestamp = Instant.now();
        System.out.println("What is value of this instant " + timestamp.toEpochMilli());
    }
}

时间戳信息里同时包含了日期和时间,这和java.util.Date很像。实际上Instant类确实等同于 Java 8之前的Date类,你可以使用Date类和Instant类各自的转换方法互相转换,例如:Date.from(Instant) 将Instant转换成java.util.Date,Date.toInstant()则是将Date类转换成Instant类。

e.g. 9. Java 8中如何使用预定义的格式化工具去解析或格式化日期


import java.time.LocalDate;
import java.time.format.DateTimeFormatter;

public class Demo17 {
    public static void main(String[] args) {
        String dayAfterTommorrow = "20180205";
        LocalDate formatted = LocalDate.parse(dayAfterTommorrow,
                DateTimeFormatter.BASIC_ISO_DATE);
        System.out.println(dayAfterTommorrow+"  格式化后的日期为:  "+formatted);
    }
}

e.g. 10. 字符串互转日期类型


import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

public class Demo18 {
    public static void main(String[] args) {
        LocalDateTime date = LocalDateTime.now();

        DateTimeFormatter format1 = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss");
        //日期转字符串
        String str = date.format(format1);

        System.out.println("日期转换为字符串:"+str);

        DateTimeFormatter format2 = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss");
        //字符串转日期
        LocalDate date2 = LocalDate.parse(str,format2);
        System.out.println("日期类型:"+date2);

    }
}

LocalDateTime基础

时间类

LocalDate yyyy-MM-dd
LocalTime HH:mm:ss
LocalDateTime yyyy-MM-dd HH:mm:ss

时间格式

常见的格式是:

yyyy-MM-dd HH:mm:ss
对应结果
2018-01-23 15:02:43

一般情况如上,那么有些特殊的地方用到特殊的用法,记不住备用以后查看

/**
日期格式化类(必须掌握)
API:
G  Era 标志符  Text  AD  
y  年  Year  1996; 96  
M  年中的月份  Month  July; Jul; 07  
w  年中的周数  Number  27  
W  月份中的周数  Number  2  
D  年中的天数  Number  189  
d  月份中的天数  Number  10  
F  月份中的星期  Number  2  
E  星期中的天数  Text  Tuesday; Tue  
a  Am/pm 标记  Text  PM  
H  一天中的小时数(0-23)  Number  0  
k  一天中的小时数(1-24)  Number  24  
K  am/pm 中的小时数(0-11)  Number  0  
h  am/pm 中的小时数(1-12)  Number  12  
m  小时中的分钟数  Number  30  
s  分钟中的秒数  Number  55  
S  毫秒数  Number  978  
z  时区  General time zone  Pacific Standard Time; PST; GMT-08:00  
Z  时区  RFC 822 time zone  -0800  
*/

yyyy-MM-dd E a HH:mm:ss

2018-01-23 星期二 下午 15:05:27

LocalDateTime时间转换

Spring MVC

Form表单请求 格式化时间

Form表单请求指的是,以QueryString方式传递参数或者Form-Data传递时的请求

  1. 字符串转LocalDateTime
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
LocalDateTime Form Request
  1. Long转LocalDateTime

增加一个Converter

import java.time.LocalDateTime;
import java.time.ZoneOffset;

import org.apache.commons.lang3.math.NumberUtils;
import org.springframework.core.convert.converter.Converter;
import org.springframework.stereotype.Component;

/**
 * @author wangqimeng
 * @date 2020/1/13 14:52
 */
@Component
public class LocalDateTimeConverter implements Converter<String, LocalDateTime> {
    @Override
    public LocalDateTime convert(String source) {
        if (!NumberUtils.isDigits(source)) {
            return null;
        }
        Long milli = NumberUtils.createLong(source);
        return LocalDateTime.ofEpochSecond(milli, 0, ZoneOffset.UTC);
    }
}
Long2LocalDateTime

注意 上下两种方式不能兼容使用 Convert级别高

Json 格式化时间

Json解析前提

maven

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-json</artifactId>
        </dependency>

or 已经有jackson 缺少


        <dependency>
            <groupId>com.fasterxml.jackson.datatype</groupId>
            <artifactId>jackson-datatype-jsr310</artifactId>
        </dependency>

相关基础注解

基础注解

    @DateTimeFormat(pattern = "yyyy-MM-dd\'T\'HH:mm:ss.SSS")
    @JsonDeserialize(using = LocalDateTimeDeserializer.class)
    @JsonSerialize(using = LocalDateTimeSerializer.class)
    @JsonFormat(pattern = "yyyy-MM-dd\'T\'HH:mm:ss.SSS")

描述:

关于Long与LocalDateTime相互转换

  1. Long转LocalDateTime
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;

import java.io.IOException;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;

/**
 * @author <a href="mailto:boommanpro@gmail.com">boommanpro</a>
 * @date 2019/7/19 14:20
 */
public class Long2LocalDateTimeDeserializer extends JsonDeserializer<LocalDateTime> {
    @Override
    public LocalDateTime deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JsonProcessingException {

        String time=jsonParser.getText();
        Instant instant = Instant.ofEpochMilli(Long.parseLong(time));
        ZoneId zone = ZoneId.systemDefault();
        return LocalDateTime.ofInstant(instant, zone);
    }
}

  1. LocalDateTime2Long
import java.io.IOException;
import java.time.LocalDateTime;
import java.time.ZoneOffset;

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;

/**
 * @author <a href="mailto:boommanpro@gmail.com">boommanpro</a>
 * @date 2019/7/19 14:20
 */
public class LocalDateTime2LongSerializer extends JsonSerializer<LocalDateTime> {

    @Override
    public void serialize(LocalDateTime value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
        gen.writeNumber(String.valueOf(value.toInstant(ZoneOffset.of("+8")).toEpochMilli()));
    }
}

Spring Date Jpa

Jpa语法查询

JPA可以根据你写的一个函数名来生成对应的SQL语句,当然函数名是要符合特定规则的。

这里介绍between和in的用法

    @Query(nativeQuery = true,
           value = "select * from z_cashier_data" +
                   "where abstract_code = ?1 " +
                   "and time BETWEEN ?2 and ?3")
    Page<CashierData> findAllabcd(String code, LocalDateTime start, LocalDateTime end, Pageable pageable);//函数名随意

相当于下面这条

    Page<CashierData> findAllByAbstractCodeAndTimeBetween(String code, LocalDateTime start, LocalDateTime end, Pageable pageable);

Specification语法

LocalDateTime start, LocalDateTime end
criteriaBuilder.between(root.get("workDay"),start,end)

Es LocalDateTime 相关注解

@JsonDeserialize(using = LocalDateTimeDeserializer.class)
@JsonSerialize(using = LocalDateTimeSerializer.class)
@Field(index = false, type = FieldType.Date, format = DateFormat.custom, pattern = "yyyy-MM-dd HH:mm:ss")