为什么使用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传递时的请求
- 字符串转LocalDateTime
 
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")

- 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);
    }
}

注意 上下两种方式不能兼容使用 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相互转换
- 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);
    }
}
- 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")