您当前的位置: 首页 > 

Dongguo丶

暂无认证

  • 2浏览

    0关注

    472博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

新时间日期 API

Dongguo丶 发布时间:2018-08-06 00:02:22 ,浏览量:2

 传统时间格式化的线程安全问
package com.dongguo.java8.date;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.*;


/**
 * @author Dongguo
 * @date 2021/8/15 0015-13:38
 * @description:java8之前时间格式化方式
 */
public class TestSimpleDateFormat {
    public static void main(String[] args) throws Exception {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");

        Callable task = new Callable() {
            @Override
            public Date call() throws Exception {
                return sdf.parse("20210816");
            }

        };
        ExecutorService pool = Executors.newFixedThreadPool(10);
        List results =new ArrayList();
        for (int i = 0; i < 10; i++) {
            //模拟并发SimpleDateFormat
            results.add(pool.submit(task));
        }
        for (Future future:results) {
            System.out.println(future.get());
        }
    }
}

 运行会发生安全问题报错

Mon Aug 16 00:00:00 CST 2021
Mon Aug 16 00:00:00 CST 2021
Mon Aug 16 00:00:00 CST 2021
Mon Aug 16 00:00:00 CST 2021
Mon Aug 16 00:00:00 CST 2021
Mon Aug 16 00:00:00 CST 2021
Mon Aug 16 00:00:00 CST 2021
Exception in thread "main" java.util.concurrent.ExecutionException: java.lang.NumberFormatException: multiple points
	at java.util.concurrent.FutureTask.report(FutureTask.java:122)
	at java.util.concurrent.FutureTask.get(FutureTask.java:192)
	at com.dongguo.java8.date.TestSimpleDateFormat.main(TestSimpleDateFormat.java:33)
Caused by: java.lang.NumberFormatException: multiple points
	at sun.misc.FloatingDecimal.readJavaFormatString(FloatingDecimal.java:1890)
	at sun.misc.FloatingDecimal.parseDouble(FloatingDecimal.java:110)
	at java.lang.Double.parseDouble(Double.java:538)
	at java.text.DigitList.getDouble(DigitList.java:169)
	at java.text.DecimalFormat.parse(DecimalFormat.java:2089)
	at java.text.SimpleDateFormat.subParse(SimpleDateFormat.java:2162)
	at java.text.SimpleDateFormat.parse(SimpleDateFormat.java:1514)
	at java.text.DateFormat.parse(DateFormat.java:364)
	at com.dongguo.java8.date.TestSimpleDateFormat$1.call(TestSimpleDateFormat.java:22)
	at com.dongguo.java8.date.TestSimpleDateFormat$1.call(TestSimpleDateFormat.java:19)
	at java.util.concurrent.FutureTask.run(FutureTask.java:266)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
	at java.lang.Thread.run(Thread.java:748)

Java8之前的解决方法:

使用ThreadLocal解决SimpleDateFormat线程安全问题

package com.dongguo.java8.date;

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * @author Dongguo
 * @date 2021/8/16 0016-8:35
 * @description:
 */
public class DateFormatThreadLocal {
    private static final ThreadLocal df = new ThreadLocal(){
        protected DateFormat initialValue(){
            return new SimpleDateFormat("yyyyMMdd");
        }
    };
    public static Date convert(String source) throws ParseException {
        return df.get().parse(source);
    }
}
package com.dongguo.java8.date;

import org.junit.jupiter.api.Test;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.*;


/**
 * @author Dongguo
 * @date 2021/8/15 0015-13:38
 * @description:java8之前时间格式化方式
 */
public class TestSimpleDateFormat {
    public static void main(String[] args) throws Exception {
        Callable task = new Callable() {
            @Override
            public Date call() throws Exception {
                return DateFormatThreadLocal.convert("20210816");
            }

        };
        ExecutorService pool = Executors.newFixedThreadPool(10);
        List results =new ArrayList();
        for (int i = 0; i < 10; i++) {
            //模拟并发SimpleDateFormat
            results.add(pool.submit(task));
        }
        for (Future future:results) {
            System.out.println(future.get());
        }
    }
}
运行结果:
Mon Aug 16 00:00:00 CST 2021
Mon Aug 16 00:00:00 CST 2021
Mon Aug 16 00:00:00 CST 2021
Mon Aug 16 00:00:00 CST 2021
Mon Aug 16 00:00:00 CST 2021
Mon Aug 16 00:00:00 CST 2021
Mon Aug 16 00:00:00 CST 2021
Mon Aug 16 00:00:00 CST 2021
Mon Aug 16 00:00:00 CST 2021
Mon Aug 16 00:00:00 CST 2021

JAVA8之后可以使用

package com.dongguo.java8.date;

import org.junit.jupiter.api.Test;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.*;


/**
 * @author Dongguo
 * @date 2021/8/15 0015-13:38
 * @description:java8时间格式化方式
 */
public class TestSimpleDateFormat {
    public static void main(String[] args) throws Exception {
        //java8 时间格式化方式
        DateTimeFormatter dtf =  DateTimeFormatter.ofPattern("yyyyMMdd");
        Callable task = new Callable() {
            @Override
            public LocalDate call() throws Exception {
                return LocalDate.parse("20210816",dtf);
            }

        };
        ExecutorService pool = Executors.newFixedThreadPool(10);
        List results =new ArrayList();
        for (int i = 0; i < 10; i++) {
            //模拟并发SimpleDateFormat
            results.add(pool.submit(task));
        }
        for (Future future:results) {
            System.out.println(future.get());
        }
    }
}

使用 LocalDate、LocalTime、LocalDateTime

LocalDate, LocalTime, LocalDateTime类的实例是不可变的对象,分别表示使用ISO-8601日历系统的日期、时间、日期和时间。它们提供了简单的日期或时间,并不包含当前的时间信息。也不包含与时区相关的信息。

注: ISO-8601日历系统是国际标准化组织制定的现代公民的日期和时间的表示法

//LocalDate, LocalTime, LocalDateTime
@Test
public void test1() {
    //获得当前时间
    LocalDateTime ldt1 = LocalDateTime.now();
    System.out.println(ldt1);
    //指定时间日期
    LocalDateTime ldt2 = LocalDateTime.of(2021, 01, 01, 23, 59, 59);
    System.out.println(ldt2);
    //日期增加2年
    LocalDateTime ldt3 = ldt1.plusYears(2);
    System.out.println(ldt3);
    //日期减2个月
    LocalDateTime ldt4 = ldt1.minusMonths(2);
    System.out.println(ldt4);

    System.out.println(ldt1.getYear());//年
    System.out.println(ldt1.getMonthValue());//月
    System.out.println(ldt1.getDayOfMonth());//日
    System.out.println(ldt1.getHour());//时
    System.out.println(ldt1.getMinute());//分
    System.out.println(ldt1.getSecond());//秒
}
运行结果:
2021-08-16T10:09:37.241
2021-01-01T23:59:59
2023-08-16T10:09:37.241
2021-06-16T10:09:37.241
2021
8
16
10
9
37

Instant 时间戳

用于“时间戳”的运算。它是以Unix元年(传统 的设定为UTC时区1970年1月1日午夜时分)开始 所经历的描述进行运算

//Instant
@Test
public void test2() {
    Instant now = Instant.now();//默认获取UTC时区
    System.out.println(now);//2021-08-16T02:13:27.666Z
    OffsetDateTime odt = now.atOffset(ZoneOffset.ofHours(8));//相差8个时区,偏移8个小时
    System.out.println(odt);
    long milli = now.toEpochMilli();//获得毫秒值
    System.out.println(milli);

    Instant instant = Instant.ofEpochSecond(1000);//从Unix元年加上1000s
    System.out.println(instant);
}
运行结果
2021-08-16T02:19:57.160Z
2021-08-16T10:19:57.160+08:00
1629080397160
1970-01-01T00:16:40Z
计算日期时间间隔Duration 和 Period

Duration:用于计算两个“时间”间隔 Period:用于计算两个“日期”间隔

Duration

    //Duration:计算两个 时间 之间的间隔
    @Test
    public void test3() {
        Instant start = Instant.now();
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        Instant end = Instant.now();
        Duration between = Duration.between(start, end);
//        System.out.println(between.getSeconds());//秒
        System.out.println(between.toMillis());//毫秒
    }
运行结果
1000

Period

//Period:计算两个 日期 之间的间隔
@Test
public void test4() {
    LocalDate ld1 = LocalDate.of(2020, 1, 1);
    LocalDate ld2 = LocalDate.now();
    Period period = Period.between(ld1, ld2);

    System.out.println(period.getYears());
    System.out.println(period.getMonths());
    System.out.println(period.getDays());

}
运行结果
1
7
15
时间校正器

TemporalAdjuster :时间校正器。有时我们可能需要获取例如:将日期调整到“下个周日”等操作。

TemporalAdjusters :该类通过静态方法提供了大量的常用TemporalAdjuster的实现。

@Test
public void test5() {
    LocalDateTime now = LocalDateTime.now();
    System.out.println(now);//2021-08-16T12:41:19.605
    LocalDateTime date1 = now.withDayOfMonth(10);//指定天为10号
    System.out.println(date1);//2021-08-10T12:41:19.605
    LocalDateTime date2 = now.with(TemporalAdjusters.next(DayOfWeek.SUNDAY));//下周的周日
    System.out.println(date2);//2021-08-22T12:41:19.605

    //自定义下一个工作日
    LocalDateTime date3 = now.with((d) -> {
        LocalDateTime ldt = (LocalDateTime) d;
        DayOfWeek day = ldt.getDayOfWeek();
        if (day.equals(DayOfWeek.FRIDAY)) {
            return ldt.plusDays(3);//周五 增加3天
        } else if (day.equals(DayOfWeek.SATURDAY)) {
            return ldt.plusDays(2);//周六 增加2天
        } else {
            return ldt.plusDays(1);//其他 增加1天
        }
    });
    System.out.println(date3);//2021-08-17T12:41:19.605
}
DateTimeFormatter 格式化时间/日期
@Test
public void test6() {
    DateTimeFormatter dtf = DateTimeFormatter.ISO_DATE;
    LocalDateTime now = LocalDateTime.now();
    System.out.println(now);//2021-08-16T12:57:59.397
    String date1 = now.format(dtf);
    System.out.println(date1);//2021-08-16
    System.out.println("-----------------------");
    DateTimeFormatter dtf2 = DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH::mm::ss");
    String date2 = now.format(dtf2);
    //String date3 = dtf2.format(now);
    System.out.println(date2);//2021年08月16日 12::57::59
   // System.out.println(date3);//2021年08月16日 12::57::59
    System.out.println("-----------------------");

    //将字符串日期转回LocalDateTime
    LocalDateTime newDate = LocalDateTime.parse(date3,dtf2);
    System.out.println(newDate);//2021-08-16T12:57:59
}
时区的处理

 Java8 中加入了对时区的支持,带时区的时间为分别为:ZonedDate、ZonedTime、ZonedDateTime其中每个时区都对应着 ID,地区ID都为 “{区域}/{城市}”的格式 例如 :Asia/Shanghai 等 ZoneId:该类中包含了所有的时区信息 getAvailableZoneIds() : 可以获取所有时区时区信息 of(id) : 用指定的时区信息获取 ZoneId 对象

@Test
public void test7() {
    //获得所有时区
    Set zoneIds = ZoneId.getAvailableZoneIds();
    zoneIds.forEach(System.out::println);
}
@Test
public void test8() {
    //指定时区的时间
    LocalDateTime ldt = LocalDateTime.now(ZoneId.of("US/Alaska"));
    System.out.println(ldt);//2021-08-15T21:08:46.406
    //指定时区的时间
    LocalDateTime ldt2 = LocalDateTime.now(ZoneId.of("Asia/Shanghai"));//2021-08-16T13:08:46.403
    //返回指定时区的时间与某个时区相差时区的时间
    ZonedDateTime zdt = ldt2.atZone(ZoneId.of("Chile/Continental"));
    System.out.println(zdt);//2021-08-16T13:08:46.408-04:00[Chile/Continental]
}

关注
打赏
1638062488
查看更多评论
立即登录/注册

微信扫码登录

0.6308s