• Java笔记09


    基本概念

    • 日期: 某一天, 不连续变化
    • 时间: 带日期的时间, 和不带日期的时间
    • 不带日期的时间无法确定一个唯一时刻的

    本地时间

    • 因时区问题, 全球时间并不是一致的

    时区

    • GMT/UTC加时区偏移表示
    • GMT+08:00/UTC+08:00
    • 全球时刻相同

    夏令时

    • 夏天开始的时候, 推后一个小时. 结束的时候, 再往前拨一个小时
    • 夏令时使用标准库提供的相关类, 并不需要自己计算

    本地化

    • Locale语言_国家的字母缩写构成
    • zh_CN表示中文+中国
    • en_US表示英文+美国
    • 语言小写, 国家大写
    • 不同Local, 时间表示不同
      • zh-CN: 2016-11-30
      • en_US: 11/30/2016
    • 根据Local针对当地用户习惯格式化日期, 时间, 数字, 货币等

    Date和Calendar

    数据和存储和展示

    • 定义一个整型变量并赋值
    • 编译器会把程序源码作为字符串, 编译成字节码
    • 变量n指向内存实际上一个指定大小的字节区域
    • 计算机的内存中除了二进制的0/1没有其他格式
    • 我们可以用十六进制打印这个整数
    • 也可以用特定的价格格式表示
    System.out.println(n);
    System.out.println(Integer.toHexString(n));
    System.out.println(NumberFormat.getCurrencyInstance(Locale.CHINA).format(n));
    
    • 整数是存储格式, 展示格式可以有各种形式
    • 同一时刻在计算机中存储的是同一个整数, 成为Epoch Time, 纪元时间, 时间戳
    • 表示从固定时间到现在经历的一共经历的秒数
    • 时间戳, 通常使用long
    • System.currentTimeMillis()Java获取时间戳的方式

    标准库API

    • 一套定义在java.util里面
      • Date
      • Calendar
      • TimeZone
    • 一套定义在java.time: Java 8引入
      • LocalDateTime
      • ZonedDateTime
      • ZoneId
    • 遗留代码仍然使用旧的API, 需要对旧API进行了解

    Date

    • 用于表示一个日期和时间的对象
    • SimpleDateFormat: 对Date进行转换
      • yyyy: 年
      • MM: 月
      • dd: 日
      • HH: 小时
      • mm: 分钟
      • ss: 秒
    • 不能转换时区
    • 很难对日期和时间进行加减

    Calendar

    • 获取并设置年, 月, 日, 时, 分, 秒
    • 可以做简单的日期和时间运算
    • 一获取就是当前日期, 想要设置的话, 需要先清除
    • Calendar.getTime()可以将一个Calendar对象抓换成Date对象

    TimeZone

    • 时区功能
    • 可以获取时区ID, 然后对指定时区进行转换
      • 清除所有字段
      • 设定指定时区
      • 设定日期和时间
      • 创建SimpleDateFormat并设定目标时区
      • 格式化获取的Date对象
    • 时区只能在显示的时候转换
    • add()对日期进行加减

    LocalDateTime

    • java.time包提供了新的日期和时间API
      • 本地日期和时间: LocalDateTime, LocalDate, LocalTime
      • 带有时区的日期和时间: ZonedDateTime
      • 时刻: Instant
      • 时区: ZoneId, ZoneOffset
      • 时间间隔: Duration
      • 还有一套取代SimpleDateFormat的格式化类型DateTimeFormat
    • 严格区分时刻, 本地日期, 本地时间, 和带时区的日期时间
    • 对日期和时间进行原酸更改方便
    • 修正:
      • Month: 1-12: 1月-12月
      • Week: 1-7: 周一到周日
    • 几乎都是不变类型

    再次LocalDateTime

    • 表示本地时间和日期
    • 通过of()创建指定日期和时间的LocalDateTime
    • 字符串转换为LocalDateTime就可以传入标准格式
    • 时间和日期的分隔符是T

    DateTimeFormatter

    • 自定义格式输出
    • 自定义格式解析
        // 自定义格式化
        DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss");
        System.out.println(dtf.format(LocalDateTime.now()));
    
        // 用自定义格式解析
        LocalDateTime dt2 = LocalDateTime.parse("2019/11/30 15:11:11", dtf);
        System.out.println(dt2);
    
    • 提供了对时间和时间非常简单的链式调用

    • 月份加减会自动调整日期

    • 对日期和时间进行调整可以使用withXXX()

    • 奇淫技巧

        // 本月第一天
        LocalDateTime firstDay = LocalDate.now().withDayOfMonth(1).atStartOfDay();
        System.out.println(firstDay);
        // 本月最后一天
        LocalDate lastDay = LocalDate.now().with(TemporalAdjusters.lastDayOfMonth();
        System.out.println(lastDay);
        // 下个月第一天
        LocalDate nextMonthFirstDay = LocalDate.now().with(TemporalAdjusters.firstDayOfNextMonth());
        System.out.println(nextMonthFirstDay);
        // 本月第一个周一
        LocalDate firstWeekday = LocalDate.now().with(TemporalAdjusters.firstInMonth(DayOfWeek.MONDAY));
        System.out.println(firstWeekday);
    
    • isBefore()/isAfter(): 判断两个LocalDateTime()先后.
    • 因为LocalDateTime没有时区, 无法确定某一时刻, 所以无法与时间戳进行互换
    • ZonedDateTime可以与时间戳互换

    Duration和Period

    • Duration: 表示两个时刻之间的时间间隔
    • Period: 表示两个日期之间的天数
    • 使用P...T...进行表示
    • 使用of()或者parse()可以直接创建Duration
    Duration d1 = Duration.ofHours(10);
    Duration d2 = Duration.parse("P1DT2H3M");
    

    ZonedDateTime

    • 表示带有时区的本地日期和时间
    • 创建方式:
      • 通过now()创建
      • 通过给一个LocalDateTime()附加一个ZonedId

    时区转换

    • withZoneSameInstant()进行时区转换
    • toLocalDateTime()转换成本地时间

    DateTimerFormatter

    • 使用LocalDateTime或者ZonedLocalDateTime, 使用DateTimerFormatter进行格式化
    • SimpleDateFormat不是线程安全的, 只能在方法内部创建新的局部变量
    • DateTimerFormatter是线程安全的
    • 通过传入格式化字符串实现, 或者可以同时指定Local
    • 固定字符'xxx'表示
    • toString()显示字符串默认按照ISO 8601格式
    • 可以通过DateTimeFormatter预定义的几个静态变量引用

    Instant

    • 时间戳
    • 本质上只是一个不断递增的整数
    • System.currentTimeMillis()获取
    • Instant.now()获取当前时间戳
        Instant now = Instant.now();
        System.out.println(now.getEpochSecond()); // second
        System.out.println(now.toEpochMilli()); // millisecond
    
    • 通过atZoneId, 得到ZonedDateTime
    • LocalDateTime, ZoneId, ZonedDateTime, 和long都可以互相转换
    • 留意long是毫秒, 还是秒.

    最佳实践

    • 除非遇到遗留代码, 否则应该坚持使用新API

    旧API转新API

    • Date/Calendar通过toInstant(), 转化为Instant对象
    • Instant再转换为ZonedDateTime
        // Date -> Instant
        Instant ins1 = new Date().toInstant();
    
        // Calendar -> Instant -> ZonedDateTime
        Calendar calendar = Calendar.getInstance();
        Instant ins2 = Calendar.getInstance().toInstant();
        ZonedDateTime zdt = ins2.atZone(calendar.getTimeZone().toZoneId());
    

    新API转旧API

    • 借助long型时间戳作为中转
        // ZonedDateTime -> long
        ZonedDateTime zdt = ZonedDateTime.now();
        long ts = zdt.toEpochSecond() * 1000;
    
        // long -> Date
        Date date = new Date(ts);
    
        // long -> Calendar
        Calendar calendar = Calendar.getInstance();
        calendar.clear();
        calendar.setTimeZone(TimeZone.getTimeZone(zdt.getZone().getId()));
        calendar.setTimeInMillis(zdt.toEpochSecond() * 1000);
    

    在数据库中存储日期和时间

    • 数据库类时间类型

      • DATETIME: 旧: java.util.Date; 新: LocalDateTime
      • DATE: 旧: java.sql.Date 新: LocalDate
      • TIME: 旧: java.sql.Time 新: LocalTime
      • TIMESTAMP: 旧: java.sql.Timestamp 新: LocalDateTime
    • 数据库中最好是用时刻Instant, long型表示, 数据库中存储为BIGINT

    • 然后为不同用户, 以不同的偏好进行显示

      public static void main(String[] args) {
        long ts = 1574208900000L;
        System.out.println(timestampToString(ts, Locale.CHINA, "Asia/Shanghai"));
        System.out.println(timestampToString(ts, Locale.US, "America/New_York"));
      }
      static String timestampToString(long epochMilli, Locale lo, String zoneId) {
        Instant ins = Instant.ofEpochMilli(epochMilli);
        DateTimeFormatter f = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM, FormatStyle.SHORT);
        return f.withLocale(lo).format(ZonedDateTime.ofInstant(ins, ZoneId.of(zoneId)));
      }
    
  • 相关阅读:
    [转]C#获取程序当前路径的方法
    [解决办法]未在本地计算机上注册“Mircosoft.Jet.OleDB.4.0”提供程序
    [解决办法]正在尝试使用已关闭或释放并且不再有效的 SPWeb 对象
    PowerShell学习笔记
    DNS
    在C#编程中,如何将Excel保存为2003的格式
    SAAS相关网络资源
    LCID及Culture Name列表
    Microsoft's naming conventions (微软命名规范)
    C#中如何结束Excel (Office)进程
  • 原文地址:https://www.cnblogs.com/zhangrunhao/p/12767118.html
Copyright © 2020-2023  润新知