热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Java使用DateTimeFormatter实现格式化时间

这篇文章主要介绍了Java使用DateTimeFormatter实现格式化时间,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

用扫描器获取输入的时间(年月日时分),这个时间的格式是常用的格式,然后格式化这个时间,把格式化的时间输出到控制台,可以在控制台重复输入时间.格式化的时间参考企业微信聊天记录的展示时间.用DateTimeFormatter实现,功能如下:
同年:
不同年:
同月:月日+上午/下午+时分
同年不同月:月日+时分
今天:上午/下午+时分
明天:明天+上午/下午+时分
昨天:昨天+上午/下午+时分
包括今天在内的一周内:星期+上午/下午+时分

首先看一下测试类:

package hrkj;

import java.util.Scanner;

/**
 * 日期时间测试类
 * 
 * @author 张林琛
* @date 2020/01/10 08:35:29 * @version 1.0 */ public class DateTimeTest { public static void main(String[] args) { // 获取Scanner扫描器 Scanner sc = new Scanner(System.in); // 程序开始提示语句 Hint.HINT_STAR.print(); // 程序退出提示语句 System.out.println(Order.ORDER_EXIT.getname()); while (sc.hasNextLine()) { String str = sc.nextLine(); // 判断是否为退出指令 if (Order.ORDER_EXIT.compare(str)) { Hint.HINT_END.print(); //如果退出,则关闭扫描器 sc.close(); break; // 判断输入的是否为空格或回车 } else if (str.equals(" ") || str.equals("" + "")) { Hint.BLANK_OR_ENTER.print(); } else { // 开始处理日期时间 DateTimeTool.dateTimeFormatter(str); } Hint.HINT_STAR.print(); System.out.println(Order.ORDER_EXIT.getname()); } } }

这里比较好的一点就是,在程序结束之前,会关闭扫描器,程序开始和程序结束,都会有提示语句:

请输入正确的时间,例如:
2020-01-10 10:10   2020.01.10 10:10   2020/01/10 10:10
退出请输入:[exit, 退出]

上面效果分别对应以下两行代码:

    // 程序开始提示语句
 Hint.HINT_STAR.print();
 // 程序退出提示语句
 System.out.println(Order.ORDER_EXIT.getname());

其中[exit, 退出]单独为第二行代码,与第一行代码效果拼接在一起,值得注意的是,Hint是一个枚举类,程序开始;运行期间和结尾的提示语句,都定义为枚举值,具体如下:

package hrkj;

/**
 * 日期时间类的提示语句,用于提示错误信息
 * 
 * @author 张林琛
* @date 2020/01/10 08:39:27 * @version 1.0 */ public enum Hint { /** * 日期时间长度不合法 */ LENGTH_ILLEGAL("日期时间长度不合法,"), /** * 日期错误 */ HINT_DATE("日期输入错误,"), /** * 月份输入不合法 */ HINT_MONTH("月份输入不合法,"), /** * 大月只有31天 */ HINT_BIGMONTH("大月只有31天,"), /** * 小月只有30天 */ HINT_TINYMONTH("小月只有30天,"), /** * 平年2月只有28天 */ HINT_TINY_TWOMONTH("平年二月只有28天,"), /** * 闰年二月只有29天 */ HINT_BIG_TWOMONTH("闰年二月只有28天,"), /** * 时间错误 */ HINT_TIME("时间输入错误,"), /** * 输入空格或回车 */ BLANK_OR_ENTER("不能输入空格或直接回车,"), /** * 以空格分开日期和时间 */ DATE_BLANK_TIME("请以空格分割开日期和时间,"), /** * 开始提示语句 */ HINT_STAR("请输入正确的时间,例如:\n2020-01-10 10:10 2020.01.10 10:10 2020/01/10 10:10\n退出请输入:"), /** * 程序结束提示语句 */ HINT_END("程序结束,欢迎下次使用!"); // 定义实例变量 private final String name; /** * 单个参数构造器 * * @param name */ private Hint(String name) { this.name = name; } /** * 获取实例变量的值 * * @return name */ public String getName() { return name; } /** * 打印提示语句的方法 */ public void print() { System.out.print(name); } }

因为枚举类中定义了一个print()方法,调用此方法可直接打印枚举值.
上面说到,[exit, 退出]为退出指令,用户输入exit或退出则会关闭扫描器,接着关闭程序,在此也把退出定义为一个指令枚举类,具体实现如下:

package hrkj;

import java.util.Arrays;

/**
 * 日期时间类的指令集,用于输入相对应的指令
 * 
 * @author 张林琛
* @date 2020/01/10 08:38:05 * @version 1.0 */ public enum Order { /** * 退出指令 */ ORDER_EXIT("exit","退出"); // 定义实例变量数组name private final String[] name; /** * 形参可变的构造器 * @param name */ private Order(String... name) { this.name = name; } /** * 获取退出的指令 * @return 获取的指令 */ public String getname() { return Arrays.toString(name); } /** * 判断输入的是不是退出的指令 * @param str 输入的指令 * @return 是否是退出指令 */ public boolean compare(String str) { for (int i = 0; i

Order枚举类虽然枚举实例只有一个退出(如果有其他指令可继续添加),但枚举值为两个:退出和exit,用户输入任意一个就会达到退出的效果,在此类中定义一个比较方法,用于比较用户输入的是否与枚举值相同,用到equals()方法,之所以没有用contains()方法,是因为一旦用contains()方法,那么用户输入e,x,it,等,只要是在枚举值包含的,都可以退出.

最后便是工具类,用于格式化日期时间并输出,实现细节如下

package hrkj;

import java.time.LocalDateTime;
import java.time.MonthDay;
import java.time.Year;
import java.time.format.DateTimeFormatter;
import java.time.format.FormatStyle;
import java.util.Arrays;

/**
 * 日期时间实现类,使用DateTimeFormatter实现
 * 
 * @author 张林琛
* @date 2020/01/10 08:36:37 * @version 1.0 */ public class DateTimeTool { /** * 有31天的月份 */ static int[] bigMOnth= { 1, 3, 5, 7, 8, 10, 12 }; /** * 有30天的月份 */ static int[] tinyMOnth= { 4, 6, 9, 11 }; /** * 处理日期和时间 * * @param str */ public static void dateTimeFormatter(String str) { // 判断日期时间的长度 if (str.length() <9 || str.length() > 16) { Hint.LENGTH_ILLEGAL.print(); return; } // 判断输入的日期和时间是否以空格分割 if (str.contains(" ")) { // 创建数组来接收分割后的日期时间 String[] datetime = str.split(" "); // 获取日期 String[] date = splitDate(datetime[0]); // 判断日期长度 if (date.length != 3) { Hint.HINT_DATE.print(); return; } // 获取年 Integer y = Integer.valueOf(date[0]); // 获取月 Integer M = Integer.valueOf(date[1]); // 获取日 Integer d = Integer.valueOf(date[2]); // 判断是不是闰年 if (!handleDate(y, M, d)) { // 如果月份大于12或小于1 if (M > 12 || M <1) { Hint.HINT_MONTH.print(); return; // 如果大月天数超过31或小于1 } else if (Arrays.binarySearch(bigMonth, M) > -1 && (d <= 0 || d > 31)) { Hint.HINT_BIGMONTH.print(); return; // 如果小月天数超过30或小于1 } else if (Arrays.binarySearch(tinyMonth, M) > -1 && (d <= 0 || d > 30)) { Hint.HINT_TINYMONTH.print(); return; // 如果平年二月天数超过28或小于1 } else if (y % 4 != 0 && y % 100 != 0 && M == 2 && (d <= 0 || d > 28)) { Hint.HINT_TINY_TWOMONTH.print(); return; // 如果平年二月天数超过28或小于1 } else if (y % 400 != 0 && M == 2 && (d <= 0 || d > 28)) { Hint.HINT_TINY_TWOMONTH.print(); return; // 如果闰年二月天数超过29或小于1 } else if (y % 4 == 0 && y % 100 != 0 && M == 2 && (d <= 0 || d > 29)) { Hint.HINT_BIG_TWOMONTH.print(); return; // 如果闰年二月天数超过29或小于1 } else if (y % 400 == 0 && M == 2 && (d <= 0 || d > 29)) { Hint.HINT_BIG_TWOMONTH.print(); return; } else { return; } } // 获取时间 String time = datetime[1]; // 判断是否以正则分割 boolean b = spiltTime(time); // 如果没有以正则分割 if (!b) { Hint.HINT_TIME.print(); return; } else { // 进行日期和时间的拼接 String dateTime = y + "-" + M + "-" + d + " " + time; DateTimeFormatter ofPattern1 = DateTimeFormatter.ofPattern("y-M-d H:m"); LocalDateTime parse1 = LocalDateTime.parse(dateTime, ofPattern1); // System.out.println(parse1); // 判断是不是当年 if (y == Year.now().getValue()) { // 判断是不是当月 if (M == MonthDay.now().getMonthValue()) { // 判断是不是今天 if (d == MonthDay.now().getDayOfMonth()) { printMessage("今天 a H:m", parse1); // 判断是不是昨天 } else if (d - MonthDay.now().getDayOfMonth() == -1) { printMessage("今天 a H:m", parse1); // 判断是不是明天 } else if (d - MonthDay.now().getDayOfMonth() == 1) { printMessage("明天 a H:m", parse1); // 判断一周内的哪一天 } else if (d - MonthDay.now().getDayOfMonth() >= -7 && d - MonthDay.now().getDayOfMonth() <= -2) { printMessage("E a H:m", parse1); // 在当月内,但不在本周 } else { printMessage("M-d a H:m", parse1); } // 当前年的其他月 } else { printMessage("M-d H:m", parse1); } // 不同年的情况下 } else { DateTimeFormatter dtf = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.LONG, FormatStyle.SHORT); System.out.println(parse1.format(dtf) + "分"); } } } else { return; } } /** * 获取时间格式器并解析,打印时间 * * @param info 模式字符串 * @param localDateTime LocalDateTime对象 */ private static void printMessage(String info, LocalDateTime localDateTime) { //把模式字符串传进去,获取到DateTimeFormatter对象 DateTimeFormatter ofPattern2 = DateTimeFormatter.ofPattern(info); //用LocalDateTime对象解析获取到的DateTimeFormatter对象 System.out.println(localDateTime.format(ofPattern2)); } /** * 判断大小闰年方法 * 其中判断了平年和闰年内大月和小月的天数 * @param y 年 * @param m 月 * @param d 日 * @return true为闰年,false为平年 */ private static boolean handleDate(int y, int m, int d) { // 是闰年二月情况下 if (y % 4 == 0 && y % 100 != 0 && m == 2 && (d > 0 && d <= 29)) { return true; // 是闰年二月情况下 } else if (y % 400 == 0 && m == 2 && (d > 0 && d <= 29)) { return true; // 不是闰年,但是二月情况下 } else if (y % 4 != 0 && y % 400 != 0 && m == 2 && (d > 0 && d <= 28)) { // 不是闰年,2月28天 return true; // 不是二月,判断是否是大月 } else if (Arrays.binarySearch(bigMonth, m) > -1 && (d > 0 && d <= 31)) { return true; // 不是二月,判断是否是小月 } else if (Arrays.binarySearch(tinyMonth, m) > -1 && (d > 0 && d <= 30)) { return true; } return false; } /** * 使用正则表达式限定时间 * * @param time 需要分割的时间 * @return 分割后的结果 */ private static boolean spiltTime(String time) { String t = "([01]&#63;[0-9]{1}|[2][0-3]):[0-5]&#63;[0-9]"; return time.matches(t) &#63; true : false; } /** * 使用正则表达式限定日期 * * @param date 需要分割的日期 * @return 分割后的日期 */ private static String[] splitDate(String date) { // 分割年月日 String r = "[\\./-]{1}"; // 月份出现的位数 String s = "\\d{1,2}"; return date.matches("\\d+" + "(" + r + s + "){2}") &#63; date.split(r) : new String[0]; } }

在实现类中,使用了正则表达式(一个强大的字符串处理工具)来限定日期和时间的分隔符(. / - : 四种),输入类型(只能为数字)等,得到自己想要的日期时间格式,然后对平闰年进行判断,完成后再拼接时间.然后把获取时间格式器和解析抽象成一个方法(因为用的很多,如果不抽象成方法,会显得代码很冗长),每次使用直接调用方法.最后在不同年的情况下,使用了不同风格的时间格式化器完成格式化.

测试虽然没有任何Bug,但跨年(比如19年的12月31号是20年的1月1号的昨天),跨月(比如20年1月31号为星期五,2月2号为星期日)没有实现,如需其他需要,请自行添加逻辑实现.

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。


推荐阅读
  • Python正则表达式学习记录及常用方法
    本文记录了学习Python正则表达式的过程,介绍了re模块的常用方法re.search,并解释了rawstring的作用。正则表达式是一种方便检查字符串匹配模式的工具,通过本文的学习可以掌握Python中使用正则表达式的基本方法。 ... [详细]
  • Java容器中的compareto方法排序原理解析
    本文从源码解析Java容器中的compareto方法的排序原理,讲解了在使用数组存储数据时的限制以及存储效率的问题。同时提到了Redis的五大数据结构和list、set等知识点,回忆了作者大学时代的Java学习经历。文章以作者做的思维导图作为目录,展示了整个讲解过程。 ... [详细]
  • 本文详细介绍了Java中vector的使用方法和相关知识,包括vector类的功能、构造方法和使用注意事项。通过使用vector类,可以方便地实现动态数组的功能,并且可以随意插入不同类型的对象,进行查找、插入和删除操作。这篇文章对于需要频繁进行查找、插入和删除操作的情况下,使用vector类是一个很好的选择。 ... [详细]
  • Java中包装类的设计原因以及操作方法
    本文主要介绍了Java中设计包装类的原因以及操作方法。在Java中,除了对象类型,还有八大基本类型,为了将基本类型转换成对象,Java引入了包装类。文章通过介绍包装类的定义和实现,解答了为什么需要包装类的问题,并提供了简单易用的操作方法。通过本文的学习,读者可以更好地理解和应用Java中的包装类。 ... [详细]
  • 先看官方文档TheJavaTutorialshavebeenwrittenforJDK8.Examplesandpracticesdescribedinthispagedontta ... [详细]
  • 如何自行分析定位SAP BSP错误
    The“BSPtag”Imentionedintheblogtitlemeansforexamplethetagchtmlb:configCelleratorbelowwhichi ... [详细]
  • Java太阳系小游戏分析和源码详解
    本文介绍了一个基于Java的太阳系小游戏的分析和源码详解。通过对面向对象的知识的学习和实践,作者实现了太阳系各行星绕太阳转的效果。文章详细介绍了游戏的设计思路和源码结构,包括工具类、常量、图片加载、面板等。通过这个小游戏的制作,读者可以巩固和应用所学的知识,如类的继承、方法的重载与重写、多态和封装等。 ... [详细]
  • 本文介绍了lua语言中闭包的特性及其在模式匹配、日期处理、编译和模块化等方面的应用。lua中的闭包是严格遵循词法定界的第一类值,函数可以作为变量自由传递,也可以作为参数传递给其他函数。这些特性使得lua语言具有极大的灵活性,为程序开发带来了便利。 ... [详细]
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
  • SpringBoot uri统一权限管理的实现方法及步骤详解
    本文详细介绍了SpringBoot中实现uri统一权限管理的方法,包括表结构定义、自动统计URI并自动删除脏数据、程序启动加载等步骤。通过该方法可以提高系统的安全性,实现对系统任意接口的权限拦截验证。 ... [详细]
  • 猜字母游戏
    猜字母游戏猜字母游戏——设计数据结构猜字母游戏——设计程序结构猜字母游戏——实现字母生成方法猜字母游戏——实现字母检测方法猜字母游戏——实现主方法1猜字母游戏——设计数据结构1.1 ... [详细]
  • [大整数乘法] java代码实现
    本文介绍了使用java代码实现大整数乘法的过程,同时也涉及到大整数加法和大整数减法的计算方法。通过分治算法来提高计算效率,并对算法的时间复杂度进行了研究。详细代码实现请参考文章链接。 ... [详细]
  • Java学习笔记之面向对象编程(OOP)
    本文介绍了Java学习笔记中的面向对象编程(OOP)内容,包括OOP的三大特性(封装、继承、多态)和五大原则(单一职责原则、开放封闭原则、里式替换原则、依赖倒置原则)。通过学习OOP,可以提高代码复用性、拓展性和安全性。 ... [详细]
  • 多维数组的使用
    本文介绍了多维数组的概念和使用方法,以及二维数组的特点和操作方式。同时还介绍了如何获取数组的长度。 ... [详细]
  • JDK源码学习之HashTable(附带面试题)的学习笔记
    本文介绍了JDK源码学习之HashTable(附带面试题)的学习笔记,包括HashTable的定义、数据类型、与HashMap的关系和区别。文章提供了干货,并附带了其他相关主题的学习笔记。 ... [详细]
author-avatar
Yy石小雪
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有