天天看点

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

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

<b>根据指定格式的字符串,转换为 date(可研究根据指定格式的字符串,转化为其他指定的类型,如 json 转换为 javabean)</b>     需要使用到的特殊类:import java.text.parseposition; <code>    /**</code>

<code>    </code><code>* &lt;p&gt;parses a string representing a date by trying a variety of different parsers.</code>

<code>    </code><code>*</code>

<code>    </code><code>* &lt;p&gt;the parse will try each parse pattern in turn.</code>

<code>    </code><code>* a parse is only deemed successful if it parses the whole of the input string.</code>

<code>    </code><code>* if no parse patterns match, a parseexception is thrown.</code>

<code>    </code><code>* @param str  the date to parse, not null</code>

<code>    </code><code>* @param parsepatterns  the date format patterns to use, see simpledateformat, not null</code>

<code>    </code><code>* @param lenient specify whether or not date/time parsing is to be lenient.</code>

<code>    </code><code>* @return the parsed date</code>

<code>    </code><code>* @throws illegalargumentexception if the date string or pattern array is null</code>

<code>    </code><code>* @throws parseexception if none of the date patterns were suitable</code>

<code>    </code><code>* @see java.util.calender#islenient()</code>

<code>    </code><code>*/</code>

<code>   </code><code>private</code> <code>static</code> <code>date parsedatewithleniency(</code>

<code>           </code><code>string str, string[] parsepatterns,</code><code>boolean</code> <code>lenient)</code><code>throws</code> <code>parseexception {</code>

<code>       </code><code>if</code> <code>(str ==</code><code>null</code> <code>|| parsepatterns ==</code><code>null</code><code>) {</code>

<code>           </code><code>throw</code> <code>new</code> <code>illegalargumentexception(</code><code>"date and patterns must not be null"</code><code>);</code>

<code>       </code><code>}</code>

<code>       </code> 

<code>       </code><code>simpledateformat parser =</code><code>new</code> <code>simpledateformat();</code>

<code>       </code><code>parser.setlenient(lenient);</code>

<code>       </code><code>parseposition pos =</code><code>new</code> <code>parseposition(</code><code>0</code><code>);</code>

<code>       </code><code>for</code> <code>(string parsepattern : parsepatterns) {</code>

<code>           </code><code>string pattern = parsepattern;</code>

<code>           </code><code>// lang-530 - need to make sure 'zz' output doesn't get passed to simpledateformat</code>

<code>           </code><code>if</code> <code>(parsepattern.endswith(</code><code>"zz"</code><code>)) {</code>

<code>               </code><code>pattern = pattern.substring(</code><code>0</code><code>, pattern.length() -</code><code>1</code><code>);</code>

<code>           </code><code>}</code>

<code>           </code> 

<code>           </code><code>parser.applypattern(pattern);</code>

<code>           </code><code>pos.setindex(</code><code>0</code><code>);</code>

<code>           </code><code>string str2 = str;</code>

<code>           </code><code>// lang-530 - need to make sure 'zz' output doesn't hit simpledateformat as it will parseexception</code>

<code>               </code><code>str2 = str.replaceall(</code><code>"([-+][0-9][0-9]):([0-9][0-9])$"</code><code>,</code><code>"$1$2"</code><code>);</code>

<code>           </code><code>date date = parser.parse(str2, pos);</code>

<code>           </code><code>if</code> <code>(date !=</code><code>null</code> <code>&amp;&amp; pos.getindex() == str2.length()) {</code>

<code>               </code><code>return</code> <code>date;</code>

<code></code>

<code>       </code><code>throw</code> <code>new</code> <code>parseexception(</code><code>"unable to parse the date: "</code> <code>+ str, -</code><code>1</code><code>);</code>

<code>   </code><code>}</code>

<code>    在 java 日期格式里,"zz" 代表的是 时区。在java 里,格式化需要借助类 formate,同时,parse 的时候一般需要借助类 parseposition,</code><code>parseposition</code> 是 <code>format</code> 及其子类所使用的简单类,用来在解析过程中跟踪当前位置。各种 <code>format</code> 类中的 <code>parseobject</code> 方法要求将 <code>parseposition</code>对象作为一个变量。

    日期解释的宽松性:

<code>    calendar</code> 有两种解释日历字段的模式,即 lenient 和 non-lenient。当 <code>calendar</code> 处于 lenient 模式时,它可接受比它所生成的日历字段范围更大范围内的值。当 <code>calendar</code> 重新计算日历字段值,以便由 <code>get()</code> 返回这些值时,所有日历字段都被标准化。例如,lenient 模式下的<code>gregoriancalendar</code> 将 <code>month == january</code>、<code>day_of_month == 32</code> 解释为 february 1。

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

<b>日期加减(calendar 的 add &amp;&amp; set &amp;&amp; roll)</b> 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

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

<code>private</code> <code>static</code> <code>date set(date date,</code><code>int</code> <code>calendarfield,</code><code>int</code> <code>amount) {</code>

<code>       </code><code>if</code> <code>(date ==</code><code>null</code><code>) {</code>

<code>           </code><code>throw</code> <code>new</code> <code>illegalargumentexception(</code><code>"the date must not be null"</code><code>);</code>

<code>       </code><code>// getinstance() returns a new object, so this method is thread safe.</code>

<code>       </code><code>calendar c = calendar.getinstance();</code>

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

<code>       </code><code>c.settime(date);</code>

<code>       </code><code>c.set(calendarfield, amount);</code>

<code>       </code><code>return</code> <code>c.gettime();</code>

<code>   </code><code>}  </code>

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

<code>private</code> <code>static</code> <code>date add(date date,</code><code>int</code> <code>calendarfield,</code><code>int</code> <code>amount) {</code>

<code>       </code><code>c.add(calendarfield, amount);</code>

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

<code>private</code> <code>static</code> <code>date roll(date date,</code><code>int</code> <code>calendarfield,</code><code>int</code> <code>amount) {</code>

<code>       </code><code>c.roll(calendarfield, amount);</code>

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

<code>public</code> <code>static</code> <code>date setminutes(date date,</code><code>int</code> <code>amount) {</code>

<code>       </code><code>return</code> <code>set(date, calendar.minute, amount);</code>

借助calendar 提供的 api ,我们可以获取一些特殊的日期值。如下面这些日期值:      如:get(int fiele) 获取给定日历字段的值;getfirstdayofweek() 获取一星期的第一天的值(1~7)(在不同的地区,每周的第一天会有所不一样,在中是默认一星期的第一天是周日 1)。通过这两个 函数,我们可以获取任意一天其所在周的第一天的日期值,如 20140902 周二,我们可以获取到周日的日期值为 20140831。具体方法如下:     构造一个 20140902 的 calendar,通过 getfirstdayofweek() ,获取本周第一天的值(返回1),通过  get(calendar.day_of_week) 获取当前日期是本周的第几天,进而获取天数差,再将当前日期减去天数差,即可获取本周第一天的日期值。     函数如下:

<code>public</code> <code>static</code> <code>date getfirstdateofweek(date date){</code>

<code>       </code><code>// 获取本周第一天的值</code>

<code>       </code><code>int</code> <code>firstdayofweek = c.getfirstdayofweek();</code>

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

<code>       </code><code>int</code> <code>dayofweek = c.get(calendar.day_of_week);</code>

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

<code>       </code><code>if</code> <code>(firstdayofweek &lt; dayofweek) {</code>

<code>           </code><code>day_diff = math.abs(dayofweek-firstdayofweek)  +</code><code>1</code><code>;</code>

<code>       </code><code>c.add(calendar.date,</code><code>1</code><code>-day_diff);</code>

<code></code> 为了本地化,我们可以用 gregoriancalendar 构造 calendar, gregoriancalendar calendar = new gregoriancalendar(local.getdefault());

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

<code>public</code> <code>static</code> <code>date getlastdateofweek(date date){</code>

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

<code>           </code><code>day_diff =math.abs(dayofweek - firstdayofweek) +</code><code>1</code><code>;</code>

<code>       </code><code>c.add(calendar.date,</code><code>7</code><code>-day_diff);</code>

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

<code>public</code> <code>static</code> <code>date getfirstdateofmonth(date date){</code>

<code>       </code><code>// get the min date in this month</code>

<code>       </code><code>int</code> <code>min_day = c.getactualminimum(calendar.date);</code>

<code>       </code><code>c.set(calendar.date, min_day);</code>

<code>   </code> 

<code>   </code><code>public</code> <code>static</code> <code>date getlastdateofmonth(date date){</code>

<code>       </code><code>//get the max date in the month</code>

<code>       </code><code>int</code> <code>max_day = c.getactualmaximum(calendar.date);</code>

<code>       </code><code>c.set(calendar.date, max_day);</code>

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

<code>//      // 获取本周第一天的值</code> <code>//      int firstdayofweek = c.getfirstdayofweek();</code> <code>//      // 当前日期是本周的第几天</code> <code>//      int dayofweek = c.get(calendar.day_of_week);</code> <code>//     </code> <code>//      int day_diff = 1;//天数差的绝对值,20140901~20140903 天数差为3</code> <code>//     </code> <code>//      if (firstdayofweek &lt; dayofweek) {</code> <code>//          day_diff = math.abs(dayofweek-firstdayofweek)  + 1;</code> <code>//      }</code> <code>//     </code> <code>//      c.add(calendar.date,1-day_diff);</code>

<code>       </code><code>int</code> <code>min_day = c.getactualminimum(calendar.day_of_week);</code>

<code>       </code><code>c.set(calendar.day_of_week,min_day);</code>

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

    在这里再谈一下,如果获取季度的起始/结束日期,方法如下:     对于给定的日期,如果我们可以获取到其所在季度的起始月份和结束月份,自然就可以获取到季度的起始日期和结束日期。函数如下:     在这里我们初始化静态数组,用来存储每个月所在季度第一个和最后一个月份的值,注意在 java 里,月份的范围是[0,11]

<code>private</code> <code>static</code> <code>final</code> <code>int</code><code>[] seasonfirstmonth =</code><code>new</code> <code>int</code><code>[] {</code><code>0</code><code>,</code><code>0</code><code>,</code><code>0</code><code>,</code><code>3</code><code>,</code><code>3</code><code>,</code><code>3</code><code>,</code>

<code>       </code><code>6</code><code>,</code><code>6</code><code>,</code><code>6</code><code>,</code><code>9</code><code>,</code><code>9</code><code>,</code><code>9</code> <code>};</code>

<code>   </code><code>private</code> <code>static</code> <code>final</code> <code>int</code><code>[] seasonlastmonth =</code><code>new</code> <code>int</code><code>[] {</code><code>2</code><code>,</code><code>2</code><code>,</code><code>2</code><code>,</code><code>5</code><code>,</code><code>5</code><code>,</code><code>5</code><code>,</code>

<code>       </code><code>8</code><code>,</code><code>8</code><code>,</code><code>8</code><code>,</code><code>11</code><code>,</code><code>11</code><code>,</code><code>11</code> <code>};</code>

<code>   </code><code>public</code> <code>static</code> <code>date getfirstdateofseason(date date){</code>

<code>       </code><code>c.set(calendar.month, seasonfirstmonth[c.get(calendar.month)]);</code>

<code>       </code><code>c.set(calendar.date, c.getactualminimum(calendar.date));</code>

<code>   </code><code>public</code> <code>static</code> <code>date getlastdateofseason(date date){</code>

<code>       </code><code>c.set(calendar.month, seasonlastmonth[c.get(calendar.month)]);</code>

<code>       </code><code>c.set(calendar.date, c.getactualmaximum(calendar.date));</code>

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

<code>public</code> <code>static</code> <code>long</code> <code>getdaysbetweentwodate(date date1,date date2){</code>

<code>       </code><code>if</code> <code>(date1 ==</code><code>null</code> <code>|| date2 ==</code><code>null</code><code>) {</code>

<code>           </code><code>throw</code> <code>new</code> <code>illegalargumentexception(</code><code>"date1 and date2 must not be null"</code><code>);</code>

<code>       </code><code>calendar c1 = calendar.getinstance();</code>

<code>       </code><code>c1.settime(date1);</code>

<code>       </code><code>calendar c2 = calendar.getinstance();</code>

<code>       </code><code>c2.settime(date2);</code>

<code>       </code><code>long</code> <code>mills_one_day =</code><code>60</code> <code>*</code><code>60</code> <code>*</code><code>24</code> <code>*</code><code>1000</code><code>;</code>

<code>       </code><code>return</code> <code>math.abs(c1.gettimeinmillis() - c2.gettimeinmillis())/mills_one_day +</code><code>1</code><code>;</code>

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