日期(字符串转日期,日期转字符串,日期加减)

这几天在研究字符串与指定类型的转换,阴差阳错地研究起 java 的日期应用了,记录下来,希望你有帮助。

  • 根据指定格式的字符串,转换为 Date(可研究根据指定格式的字符串,转化为其他指定的类型,如 json 转换为 javaBean)

需要使用到的特殊类:import java.text.ParsePosition;

    /**

     * <p>Parses a string representing a date by trying a variety of different parsers.

     *

     * <p>The parse will try each parse pattern in turn.

     * A parse is only deemed successful if it parses the whole of the input string.

     * If no parse patterns match, a ParseException is thrown.

     *

     * @param str  the date to parse, not null

     * @param parsePatterns  the date format patterns to use, see SimpleDateFormat, not null

     * @param lenient Specify whether or not date/time parsing is to be lenient.

     * @return the parsed date

     * @throws IllegalArgumentException if the date string or pattern array is null

     * @throws ParseException if none of the date patterns were suitable

     * @see java.util.Calender#isLenient()

     */

    private static Date parseDateWithLeniency(

            String str, String[] parsePatterns, boolean lenient) throws ParseException {

        if (str == null || parsePatterns == null) {

            throw new IllegalArgumentException("Date and Patterns must not be null");

        }

       

        SimpleDateFormat parser = new SimpleDateFormat();

        parser.setLenient(lenient);

        ParsePosition pos = new ParsePosition(0);

        for (String parsePattern : parsePatterns) {

            String pattern = parsePattern;

            // LANG-530 - need to make sure ‘ZZ‘ output doesn‘t get passed to SimpleDateFormat

            if (parsePattern.endsWith("ZZ")) {

                pattern = pattern.substring(0, pattern.length() - 1);

            }

           

            parser.applyPattern(pattern);

            pos.setIndex(0);

            String str2 = str;

            // LANG-530 - need to make sure ‘ZZ‘ output doesn‘t hit SimpleDateFormat as it will ParseException

            if (parsePattern.endsWith("ZZ")) {

                str2 = str.replaceAll("([-+][0-9][0-9]):([0-9][0-9])$", "$1$2");

            }

            Date date = parser.parse(str2, pos);

            if (date != null && pos.getIndex() == str2.length()) {

                return date;

            }

        }


        throw new ParseException("Unable to parse the date: " + str, -1);

    }


    在 java 日期格式里,"ZZ" 代表的是 时区。在java 里,格式化需要借助类 Formate,同时,parse 的时候一般需要借助类 parsePosition,ParsePositionFormat 及其子类所使用的简单类,用来在解析过程中跟踪当前位置。各种 Format 类中的 parseObject 方法要求将 ParsePosition对象作为一个变量。

日期解释的宽松性:

    Calendar 有两种解释日历字段的模式,即 lenientnon-lenient。当 Calendar 处于 lenient 模式时,它可接受比它所生成的日历字段范围更大范围内的值。当 Calendar 重新计算日历字段值,以便由 get() 返回这些值时,所有日历字段都被标准化。例如,lenient 模式下的GregorianCalendarMONTH == JANUARYDAY_OF_MONTH == 32 解释为 February 1。

Calendar 处于 non-lenient 模式时,如果其日历字段中存在任何不一致性,它都会抛出一个异常。例如,GregorianCalendar 总是在 1 与月份的长度之间生成 DAY_OF_MONTH 值。如果已经设置了任何超出范围的字段值,那么在计算时间或日历字段值时,处于 non-lenient 模式下的GregorianCalendar 会抛出一个异常。(在 non-lenient状态下,可以用来检测用户输入的日期是否合法)

  • 日期加减(Calendar 的 add && set && roll)

set(int field,int amount) 方法,并不会立刻就计算出新的日期的值,而是在调用 getXxx() , add(),roll() 方法才会计算出新的日期的值,即多次调用set 方法,也不会产生多余的计算。

add(int filed, int amount) 方法,调用 add 方法,会立刻计算出新的日期的值。

roll(int fielde,int amount) 方法,调用 roll 方法,也会立刻计算出新的日期的值,与 add 不同的是,在进行计算完之后,不更改更高字段的值。

举例如下:假设一个日期(Calendar类型)是date 20140831

1)调用date.set(Calendar.Month,Calendar.September),在调用 set(Calendar.Data,1) ,c.getTime() 返回的时间是 20140901

2)调用date.add(Calendar.Month,1), c.getTime() 返回的日期是,20141001。(如果是设置了 c.setLeniency(true),返回的日期是 20141001,如果是设置了 c.setLeniency(false),返回的是 20140930)

3)调用date.roll(Calendar.Month,13),c.setLeniency(flase), c.getTime() 返回的日期是 20140930,请注意这里返回的不是 20141231

对于设置日期的值,可以这样编写代码:

private static Date set(Date date, int calendarField, int amount) {

        if (date == null) {

            throw new IllegalArgumentException("The date must not be null");

        }

        // getInstance() returns a new object, so this method is thread safe.

        Calendar c = Calendar.getInstance();

        c.setLenient(false);// 这里使用严格模式,要求设置日期的值必须正确

        c.setTime(date);

        c.set(calendarField, amount);

        return c.getTime();

    }  

加减日期,可以这样编写代码:

private static Date add(Date date, int calendarField, int amount) {

        if (date == null) {

            throw new IllegalArgumentException("The date must not be null");

        }

        Calendar c = Calendar.getInstance();

        c.setTime(date);

        c.add(calendarField, amount);

        return c.getTime();

    }

roll 日期,可以这样编写代码:

private static Date roll(Date date, int calendarField, int amount) {

        if (date == null) {

            throw new IllegalArgumentException("The date must not be null");

        }

        Calendar c = Calendar.getInstance();

        c.setTime(date);

        c.roll(calendarField, amount);

        return c.getTime();

    }


对应的设置年、月、日、时、分、秒,可以这样编写代码:(其他的可以仿写)

public static Date setMinutes(Date date, int amount) {

        return set(date, Calendar.MINUTE, amount);

    }

  • 借助Calendar 提供的 api ,我们可以获取一些特殊的日期值。如下面这些日期值:

如:get(int fiele) 获取给定日历字段的值;getFirstDayOfWeek() 获取一星期的第一天的值(1~7)(在不同的地区,每周的第一天会有所不一样,在中是默认一星期的第一天是周日 1)。通过这两个 函数,我们可以获取任意一天其所在周的第一天的日期值,如 20140902 周二,我们可以获取到周日的日期值为 20140831。具体方法如下:

构造一个 20140902 的 Calendar,通过 getFirstDayOfWeek() ,获取本周第一天的值(返回1),通过  get(Calendar.day_of_week) 获取当前日期是本周的第几天,进而获取天数差,再将当前日期减去天数差,即可获取本周第一天的日期值。

函数如下:

public static Date getFirstDateOfWeek(Date date){

        Calendar c = Calendar.getInstance();

        c.setTime(date);

        // 获取本周第一天的值

        int firstDayOfWeek = c.getFirstDayOfWeek();

        // 当前日期是本周的第几天

        int dayOfWeek = c.get(Calendar.DAY_OF_WEEK);

       

        int day_diff = 1;//天数差的绝对值,20140901~20140903 天数差为3

       

        if (firstDayOfWeek < dayOfWeek) {

            day_diff = Math.abs(dayOfWeek-firstDayOfWeek)  + 1;

        }

       

        c.add(Calendar.DATE,1-day_diff);

       

        return c.getTime();

    }


为了本地化,我们可以用 GregorianCalendar 构造 Calendar,

GregorianCalendar calendar = new GregorianCalendar(Local.getDefault());

类似地,我们可以得到本周最后一天的日期:

public static Date getLastDateOfWeek(Date date){

        Calendar c = Calendar.getInstance();

        c.setTime(date);

        // 获取本周第一天的值

        int firstDayOfWeek = c.getFirstDayOfWeek();

        // 当前日期是本周的第几天

        int dayOfWeek = c.get(Calendar.DAY_OF_WEEK);

       

        int day_diff = 1;//天数差的绝对值

       

        if (firstDayOfWeek < dayOfWeek) {

            day_diff =Math.abs(dayOfWeek - firstDayOfWeek) + 1;

        }

       

        c.add(Calendar.DATE, 7-day_diff);

       

        return c.getTime();

    }

再借助 getActualMaximum(int field) 给定此 Calendar 的时间值,返回指定日历字段可能拥有的最大值。getActualMinimum(int field)  给定此 Calendar 的时间值,返回指定日历字段可能拥有的最小值。借助这两个函数,我们可以获取一天所在月的第一天/最后一天的日期。方法如下:

public static Date getFirstDateOfMonth(Date date){

        if (date == null) {

            throw new IllegalArgumentException("the date must not be null");

        }

       

        Calendar c = Calendar.getInstance();

        c.setTime(date);

        // get the min date in this month

        int min_day = c.getActualMinimum(Calendar.DATE);

        c.set(Calendar.DATE, min_day);

       

        return c.getTime();

    }

   

    public static Date getLastDateOfMonth(Date date){

        if (date == null) {

            throw new IllegalArgumentException("the date must not be null");

        }

       

        Calendar c = Calendar.getInstance();

        c.setTime(date);

        //get the max date in the month

        int max_day = c.getActualMaximum(Calendar.DATE);

        c.set(Calendar.DATE, max_day);

       

        return c.getTime();

    }

聪明的我们,是否马上就会想到,能否通过 getActualMaximum 和 getActualMininum 来获取一周 day_of_week 的最大/小值呢??是的,通过这两个方法,我们可以减少一定的计算量,如下:

public static Date getFirstDateOfWeek(Date date){

        Calendar c = Calendar.getInstance();

        c.setTime(date);

//      // 获取本周第一天的值

//      int firstDayOfWeek = c.getFirstDayOfWeek();

//      // 当前日期是本周的第几天

//      int dayOfWeek = c.get(Calendar.DAY_OF_WEEK);

//     

//      int day_diff = 1;//天数差的绝对值,20140901~20140903 天数差为3

//     

//      if (firstDayOfWeek < dayOfWeek) {

//          day_diff = Math.abs(dayOfWeek-firstDayOfWeek)  + 1;

//      }

//     

//      c.add(Calendar.DATE,1-day_diff);

       

        int min_day = c.getActualMinimum(Calendar.DAY_OF_WEEK);

        c.set(Calendar.DAY_OF_WEEK,min_day);

       

        return c.getTime();

    }

借助 getActualMaxinum 和 getActualMininum 可以获得很多最大/小值,如可以获取月、日、时、分、秒的最后/最初一刻,自然就可以获取一年的起始/结束日期,一天的起始/结束时刻等等,发挥想象了,灵活应用 api,就可以很多我们所需要的函数,组织起来就可以是一个 工具类了。

在这里再谈一下,如果获取季度的起始/结束日期,方法如下:

对于给定的日期,如果我们可以获取到其所在季度的起始月份和结束月份,自然就可以获取到季度的起始日期和结束日期。函数如下:

在这里我们初始化静态数组,用来存储每个月所在季度第一个和最后一个月份的值,注意在 java 里,月份的范围是[0,11]

private static final int[] seasonFirstMonth = new int[] { 0, 0, 0, 3, 3, 3,

        6, 6, 6, 9, 9, 9 };

    private static final int[] seasonLastMonth = new int[] { 2, 2, 2, 5, 5, 5,

        8, 8, 8, 11, 11, 11 };

   

    public static Date getFirstDateOfSeason(Date date){

        if (date == null) {

            throw new IllegalArgumentException("the date must not be null");

        }

       

        Calendar c = Calendar.getInstance();

        c.setTime(date);

       

        c.set(Calendar.MONTH, seasonFirstMonth[c.get(Calendar.MONTH)]);

        c.set(Calendar.DATE, c.getActualMinimum(Calendar.DATE));

        return c.getTime();

    }

   

    public static Date getLastDateOfSeason(Date date){

        if (date == null) {

            throw new IllegalArgumentException("the date must not be null");

        }

       

        Calendar c = Calendar.getInstance();

        c.setTime(date);

       

        c.set(Calendar.MONTH, seasonLastMonth[c.get(Calendar.MONTH)]);

        c.set(Calendar.DATE, c.getActualMaximum(Calendar.DATE));

        return c.getTime();

    }

最后谈一下,如何去计算两个日期之间的天数差(规定如下,20140901~20140903,天数差为3),函数如下:

public static long getDaysBetweenTwoDate(Date date1,Date date2){

        if (date1 == null || date2 == null) {

            throw new IllegalArgumentException("date1 and date2 must not be null");

        }

       

        Calendar c1 = Calendar.getInstance();

        c1.setTime(date1);

       

        Calendar c2 = Calendar.getInstance();

        c2.setTime(date2);

       

        long mills_one_day = 60 * 60 * 24 * 1000;

       

        return Math.abs(c1.getTimeInMillis() - c2.getTimeInMillis())/mills_one_day + 1;

    }


附:通过阅读 Java API,借助一些基础的推算逻辑,我们可以合成很多很有用工具类,让我们彼此一起努力。在这一次学习当中,本人更感兴趣的,如何通过指定的字符串格式构造指定的对象(如通过字符串构造日期),又如何通过指定格式输出制定对象(如根据 yyyyMMdd 格式输出 日期对象)。

时间: 2024-11-09 12:47:43

日期(字符串转日期,日期转字符串,日期加减)的相关文章

Sql日期时间格式转换大全集,SQL加减一个月,加减一天,SQL时间格式转换。

语句及查询结果: Select CONVERT(varchar(100), GETDATE(), 0): 05 16 2006 10:57AM Select CONVERT(varchar(100), GETDATE(), 1): 05/16/06 Select CONVERT(varchar(100), GETDATE(), 2): 06.05.16 Select CONVERT(varchar(100), GETDATE(), 3): 16/05/06 Select CONVERT(varc

ORACLE PL/SQL 字符串函数、数学函数、日期函数

ORACLE PL/SQL 字符串函数.数学函数.日期函数 --[字符串函数] --字符串截取substr(字段名,起始点,个数) select Name,substr(Name,2,4),substr(Name,0,3),substr(Name,-2,3),substr(Name,-2,1) from t1; --字符串从前面取三个(0开始) select Name,substr(Name,0,3) from t1; --字符串从后面取三个 select Name,substr(Name,-3

sql:日期操作注意的,如果以字符串转日期时的函数,因为数据量大,会出问题

---1.以日期字符操作转换日期 如果是VIP1生日不对,可以以上传的数据日期为生日 begin declare @NowBirthday datetime, @birthday datetime,@stat datetime,@end datetime,@statbirthday datetime,@endbirthday datetime,@thirdbirthday datetime,@firthbirthday datetime, @year int,@month int , @day

获取周 星期 的第一天 最后一天 或者 月的 日期(字符串转日期,日期转字符串,日期加减)

获取周的第一天,最后一天 System.out.println(getStartEndDate("2016-05-01", 1)); 获取星期的第一天和最后一天 System.out.println(getStartEndDate("2016-05-01", 0)); public static String getStartEndDate(String aDay, int type) { SimpleDateFormat df = new SimpleDateFo

Python中的日期的加减如何实现?

本文和大家分享的主要是python中日期加减操作相关内容,一起来看看吧,希望对大家学习python有所帮助. 1. 日期输出格式化 所有日期.时间的api都在datetime模块内. 1. datetime => string now = datetime.datetime.now() now.strftime('%Y-%m-%d %H:%M:%S')#输出2012-03-05 16:26:23.870105 strftime是datetime类的实例方法. 2. string => date

日期加减js,天数组增加,日期自动修改

最近在弄火车票的项目,因为火车票选日期最大范围是20天,所要要控制在当前时间的20天内的一个日期 开始在网上找了一个直接修改Date prototype 后来领导说这样不太好,所以只能换个别的方法写 怎么写呢,思路呢,天++  转月 转年,好麻烦呀 从网上看了半天太难找了,后来看看时间转化 还是想着把当前的时间转成时间字符串,然后把当前的时间字符串相加,得一个新的时间字符串,新的时间字符串,再通过转化就成一个新的时间 大概像下面的代码 function addDay(d,s){ var m; v

Java 中日期的几种常见操作 —— 取值、转换、加减、比较

Java 的开发过程中免不了与 Date 类型纠缠,准备总结一下项目经常使用的日期相关操作,JDK 版本 1.7,如果能够帮助大家节约那么几分钟起身活动一下,去泡杯咖啡,便是极好的,嘿嘿.当然,我只提供了可行的解决方案,并不保证是最佳实践,欢迎讨论. 1. 日期取值 在旧版本 JDK 的时代,有不少代码中日期取值利用了 java.util.Date 类,但是由于 Date 类不便于实现国际化,其实从 JDK1.1 开始,就更推荐使用 java.util.Calendar 类进行时间和日期方面的处

java 常用的日期加减和日期格式化工具类

平时我们遇到日期的加减,感觉是相当麻烦的,以下是常用的日志加减的方法,包括日的加减.月的加减等,也包括了一些常用的日期格式化,这样在我们以后碰到日期加减的时候会省去很多麻烦,欢迎大神指正和吐槽: 1 package bp.util; 2 3 import java.text.ParseException; 4 import java.text.SimpleDateFormat; 5 import java.util.Calendar; 6 import java.util.Date; 7 8 p

java 日期格式转换,加减等

将string转换成日期Date SimpleDateFormat re = new SimpleDateFormat(String formate);----:yyyy-MM-dd System.out.println(re.parse("1990-02-02"));----Fri Feb 02 00:00:00 CST 1990 将日期转换成String SimpleDateFormat sfdate = new SimpleDateFormat(String formate);-