详解js中常规日期格式处理、月历渲染和倒计时函数


Posted in Javascript onDecember 28, 2016

前言

相信大家都知道日期格式处理在前端的日常任务中非常常见,但是为此引入monent.js这样的类库又会显得有点臃肿,毕竟我们一个特定的项目中,并不需要monent.js那么全的涵盖范围。另外,如果现在公司让你自己手写一个日历组件(月历、周历),日历组件中需要耦合我们的其他业务需求,如果有一个任务列表,当11月22号的待进行任务,我需要在日历上有一个绿色圆点,表示当天有待办事项。

下面介绍一些常规的函数,希望对大家有用。

月历效果图

详解js中常规日期格式处理、月历渲染和倒计时函数

函数目录

  1. getFormatDateStr 获得指定日期格式的字符串;
  2. getDayPrevAfter 获得n天前/后的日期;
  3. formatDateWithTimeZone 格式化日期带时区,ISO 8601;
  4. countDownBySecond 倒计时;
  5. monthSize 获得指定日期所在月的天数;
  6. getCalendarMonth 获得指定日期所在月的第一周到第四/五周的数据组合;
  7. getOneDateWeekIndex 获得指定的某天所在该月的第几周,下标从0开始;

下面是详细的说明:

getFormatDateStr

/**
 * [zeroPadding 小于10的数字补0,必填]
 * @param {[Int]} value [description]
 * @return {[String]} [description]
 */
export function zeroPadding(value){
 return value < 10 ? `0${value}` : value;
}

/**
 * [_isDateStrSeparatorCh 判断日期格式字符串的分隔符是否是中文]
 * @param {[String]} str [必填]
 * @return {[String]} [分隔符]
 */
function _getDateStrSeparator(str, startIndex, endIndex) {
 startIndex = startIndex ? startIndex : 4;
 endIndex = endIndex ? endIndex : 5;
 let separator = str.slice(startIndex, endIndex);
 if (separator === '年' || separator === '月' ) {
 separator = 'Ch';
 }
 return separator;
}

/**
 * [_isDateStrSeparatorCh 判断日期格式字符串的分隔符是否是中文]
 * @param {[String]} str [必填]
 * @return {[String]} [分隔符]
 */
function _isDateStrSeparatorCh(str) {
 if ( str.indexOf('年')!=-1 || str.indexOf('月')!=-1 ) {
 return true;
 }
 return false;
}

/**
 * [getFormatDateStr 获得指定日期格式的字符串]
 * @param {[String or Date]} date [要转换的日期,必填]
 * @param {[String]} dateFormatStr [要转化的目标格式,必填,2016-11-22之间的分隔符可任意,可选项:
 * 'yyyy-mm-dd hh:mm:ss','yyyy/mm/dd hh:mm:ss','yyyy.mm.dd hh:mm:ss','yyyy年mm月dd hh:mm:ss',
 * 'yyyy-mm-dd hh:mm',
 * 'mm-dd hh:mm',
 * 'yyyy-mm-dd',
 * 'mm-dd',
 * 'hh:mm:ss',
 * 'hh:mm'
 * ]
 * @return {[String]}  [时间格式字符串]
 */
export function getFormatDateStr(date, dateFormatStr) {

 if ( !(date instanceof Date) ) {
 if ( date.indexOf('-') != -1 ) {
 date.replace(/\-/g,'/');
 }
  date = new Date(date);
 }

 dateFormatStr = dateFormatStr.toLowerCase();
 if (!dateFormatStr){
 return false;
 }

 let returnStr = '',
 separator = _getDateStrSeparator(dateFormatStr),
 year = date.getFullYear(),
  month = date.getMonth() + 1,
  day = date.getDate(),
  hour = date.getHours(),
  minute = date.getMinutes(),
 second = date.getSeconds();

 if ( /^yyyy(.{1})mm(.{1})dd hh:mm:ss$/.test(dateFormatStr) ) {
 if (_isDateStrSeparatorCh(dateFormatStr)) {
 returnStr = `${year}年${zeroPadding(month)}月${zeroPadding(day)}日`;
 } else {
 separator =
 returnStr = `${year}${separator}${zeroPadding(month)}${separator}${zeroPadding(day)}`;
 }
 returnStr += ` ${zeroPadding(hour)}:${zeroPadding(minute)}:${zeroPadding(second)}`;
 } else if ( /^yyyy(.{1})mm(.{1})dd hh:mm$/.test(dateFormatStr) ) {
 if (_isDateStrSeparatorCh(dateFormatStr)) {
 returnStr = `${year}年${zeroPadding(month)}月${zeroPadding(day)}日`;
 } else {
 returnStr = `${year}${separator}${zeroPadding(month)}${separator}${zeroPadding(day)}`;
 }
 returnStr += ` ${zeroPadding(hour)}:${zeroPadding(minute)}`;
 } else if ( /^mm(.{1})dd hh:mm$/.test(dateFormatStr) ) {
 if (_isDateStrSeparatorCh(dateFormatStr)) {
 returnStr = `${zeroPadding(month)}月${zeroPadding(day)}日`;
 } else {
 separator = _getDateStrSeparator(dateFormatStr, 2, 3);
 returnStr = `${zeroPadding(month)}${separator}${zeroPadding(day)}`;
 }
 returnStr += ` ${zeroPadding(hour)}:${zeroPadding(minute)}`;
 } else if ( /^yyyy(.{1})mm(.{1})dd$/.test(dateFormatStr) ) {
 if (_isDateStrSeparatorCh(dateFormatStr)) {
 returnStr = `${year}年${zeroPadding(month)}月${zeroPadding(day)}日`;
 } else {
 returnStr = `${year}${separator}${zeroPadding(month)}${separator}${zeroPadding(day)}`;
 }
 } else if ( /^mm(.{1})dd$/.test(dateFormatStr) ) {
 if (_isDateStrSeparatorCh(dateFormatStr)) {
 returnStr = `${zeroPadding(month)}月${zeroPadding(day)}日`;
 } else {
 separator = _getDateStrSeparator(dateFormatStr, 2, 3);
 returnStr = `${zeroPadding(month)}${separator}${zeroPadding(day)}`;
 }
 } else if ( /^hh:mm:ss$/.test(dateFormatStr) ) {
 returnStr = `${zeroPadding(hour)}:${zeroPadding(minute)}:${zeroPadding(second)}`;
 } else if ( /^hh:mm$/.test(dateFormatStr) ) {
 returnStr = `${zeroPadding(hour)}:${zeroPadding(minute)}`;
 }

 return returnStr;

}

getDayPrevAfter

/**
 * [getDayPrevAfter 获得n天前/后的日期]
 * @param {[String]} date [日期,非必填参数,表示调用时的时间]
 * @param {[String]} type [前一天还是后一天,非必填参数,默认后一天]
 * @param {[Int]} daysNum [天数,非必填参数,默认一天]
 * @return {[Date]}  [description]
 */
export function getDayPrevAfter(date, type, daysNum) {

 date = date ? date : new Date();
 type = type ? type : 'after';
 daysNum = daysNum ? daysNum : 1;

 if ( !(date instanceof Date) ) {
 if ( date.indexOf('-') != -1 ) {
 date.replace(/\-/g,'/');
 }
 date = new Date(date);
 }

 let returnDate = date;
 if (type === 'prev') {
 returnDate = new Date(date.getTime() - (daysNum * 24 * 60 * 60 * 1000));
 } else if (type === 'after') {
 returnDate = new Date(date.getTime() + (daysNum * 24 * 60 * 60 * 1000));
 }
 return returnDate;

}

formatDateWithTimeZone

/**
 * [formatDateWithTimeZone 格式化日期带时区,ISO 8601]
 * @param {[Date]} date [日期,非必填参数,表示调用时的时间]
 * @return {[String]} [ISO 8601格式的日期,example: 2016-11-21T14:09:15+08:00]
 */
export function formatDateWithTimeZone(date) {

 date = date ? date : new Date();
 if ( !(date instanceof Date) ) {
 if ( date.indexOf('-') != -1 ) {
 date.replace(/\-/g,'/');
 }
 date = new Date(date);
 }

 let tzo = -date.getTimezoneOffset(),
 dif = tzo >= 0 ? '+' : '-',
 pad = function (num) {
  let norm = Math.abs(Math.floor(num));
  return zeroPadding(norm);
 };
 return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}T${pad(date.getHours())}:${pad(date.getMinutes())}:${pad(date.getSeconds())}${dif}${pad(tzo / 60)}:${pad(tzo % 60)}`;

}

countDownBySecond

/**
 * [countDownBySecond 倒计时]
 * @param {[Int]} restSeconds [剩余秒数,必填]
 * @param {[Int]} timeInterval [时间间隔,非必填,默认1000ms]
 * @param {[Function]} func [每倒计时一次,就需要执行一次的回调函数名,非必填]
 * @param {[Function]} endFun [倒计时结束需要执行的函数名,非必填]
 * @return {[null]} [无返回值]
 */
export function countDownBySecond(restSeconds, timeInterval, func, endCallback) {
 let timer = null;
 let total = restSeconds;
 timeInterval = timeInterval ? timeInterval : 1000;
 timer = setInterval(function() {
 --total;
 if (total <= 0) {
  clearInterval(timer);
  endCallback && endCallback();
 }
 func && func(total);
 }, timeInterval);
}

monthSize

/**
 * [monthSize 获得指定日期所在月的天数]
 * @param {[Date]} oDate [指定的日期,非必填,默认为当天]
 * @return {[Int]} [总天数]
 */
function monthSize(oDate) {
 oDate = oDate ? oDate : new Date();
 let year = oDate.getFullYear(),
 month = oDate.getMonth(),
 _oDate = new Date();
 _oDate.setFullYear(year);
 _oDate.setMonth(month + 1, 0);
 return _oDate.getDate();
}

getCalendarMonth

/**
 * [getCalendarMonth 获得指定日期所在月的第一周到第四/五周的数据组合,形如:
 * [{
 "date": "2016/10/30", //日期字符串
 "dateNum": 30, //日
 "isCurMonth": false, //是否当前月
 "weekIndex": 0 //是本月的第几周,下标从0开始
 },{
 "date": "2016/10/31",
 "dateNum": 31,
 "isCurMonth": false,
 "weekIndex": 0
 },{
 "date": "2016/11/1",
 "dateNum": 1,
 "day": 2,
 "isCurMonth": true,
 "isToday": false,
 "weekIndex": 0
 }]
 ]
 * @param {[Date]} param [指定的日期,非必填,默认为当天]
 * @return {[Array]} [获得指定日期所在月的第一周到第四/五周的数据组合]
 */
export function getCalendarMonth(date) {
 date = date ? date : new Date();
 let y = date.getFullYear();
 let m = date.getMonth();
 let _m;
 let firstDay = new Date(y, m, 1).getDay(); //当月第一天 周期
 let days = monthSize(date);//当月天数
 let prevMonthDays = monthSize(new Date(y, m - 1));//上月天数
 let initPrevDay = prevMonthDays - firstDay;
 let lines = Math.ceil((firstDay + days) / 7);
 _m = new Array(lines * 7);
 let nextMonthDay = 0;

 for (let i = 0; i < _m.length; i++) {
 let weekIndex = parseInt(i / 7);
 if (i < firstDay) {
  let date = ++initPrevDay;
  if (m === 0 && date > 7) {
  _m[i] = {
   isCurMonth: false,
   dateNum: date,
   weekIndex,
   date: `${y - 1}/${12}/${date}`
  };
  } else {
  _m[i] = {
   isCurMonth: false,
   dateNum: date,
   weekIndex,
   date: `${y}/${m}/${date}`
  };
  }
 } else if (i >= (firstDay + days)) {
  let date = ++nextMonthDay;

  if (m === 11 && date <= 7) {
  _m[i] = {
   isCurMonth: false,
   dateNum: date,
   weekIndex,
   date: `${y + 1}/${1}/${date}`
  };
  } else {
  _m[i] = {
   isCurMonth: false,
   dateNum: date,
   weekIndex,
   date: `${y}/${m + 2}/${date}`
  };
  }
 } else {
  let _date = i - firstDay + 1;
  let today = new Date();
  let today_y = today.getFullYear();
  let today_m = today.getMonth();
  let today_d = today.getDate();
  let isToday = today_y === y && today_m === m && today_d === _date ? true : false;
  _m[i] = {
  dateNum: _date, //日期
  day: i % 7, //周期
  weekIndex,
  isCurMonth: true,
  isToday,
  date: `${y}/${m + 1}/${_date}`
  };
 }
 }
 return _m;
}

getOneDateWeekIndex

/**
 * [getOneDateWeekIndex 获得指定的某天所在该月的第几周,下标从0开始]
 * @param {[Date]} date [指定的日期,非必填,默认为当天]
 * @return {[Int]} [在该月的第几周]
 */
export function getOneDateWeekIndex(date) {
 date = date ? date : new Date();
 let monthDays = getCalendarMonth(date);
 let dateString = getFormatDateStr(date, '/', true, false, false);
 let returnDate = monthDays.filter(item => {
 return item.date === dateString;
 });
 let weekIndex = returnDate[0].weekIndex;
 return weekIndex ? weekIndex : 0;
}

总结

以上就是这篇文章的全部内容了,用上面的函数就能够实现日期格式转换,倒计时,自定义月历等常规的需要,希望对大家的学习或者工作能有一定的帮助,如果有疑问大家可以留言交流。

Javascript 相关文章推荐
在你的网页中嵌入外部网页的方法
Apr 02 Javascript
JavaScript 关键字屏蔽实现函数
Aug 02 Javascript
jquery里的正则表达式说明
Aug 03 Javascript
js的alert弹出框出现乱码解决方案
Sep 02 Javascript
页面装载js及性能分析方法介绍
Mar 21 Javascript
JavaScript Math.ceil 方法(对数值向上取整)
Jan 09 Javascript
JS实用的动画弹出层效果实例
May 05 Javascript
jQuery插件简单实现方法
Jul 18 Javascript
JavaScript提升性能的常用技巧总结【经典】
Jun 20 Javascript
JS实现列表的响应式排版(推荐)
Sep 01 Javascript
从vue源码解析Vue.set()和this.$set()
Aug 30 Javascript
javascript数组的定义及操作实例
Nov 10 Javascript
JavaScript实现经典排序算法之冒泡排序
Dec 28 #Javascript
BootStrap Tooltip插件源码解析
Dec 27 #Javascript
获取当前月(季度/年)的最后一天(set相关操作及应用)
Dec 27 #Javascript
javascript实现文字无缝滚动
Dec 27 #Javascript
JavaScript仿聊天室聊天记录
Dec 27 #Javascript
基于jQuery实现顶部导航栏功能
Dec 27 #Javascript
js正则表达式最长匹配(贪婪匹配)和最短匹配(懒惰匹配)用法分析
Dec 27 #Javascript
You might like
PHP rawurlencode与urlencode函数的深入分析
2013/06/08 PHP
PHP文件上传主要代码讲解
2013/09/30 PHP
PHP实现数字补零功能的2个函数介绍
2014/05/12 PHP
jQuery html() in Firefox (uses .innerHTML) ignores DOM changes
2010/03/05 Javascript
JavaScript为对象原型prototype添加属性的两种方式
2010/08/01 Javascript
获取下拉列表框的值是数组,split,$.inArray示例
2013/11/13 Javascript
JavaScript学习小结(7)之JS RegExp
2015/11/29 Javascript
学习javascript面向对象 理解javascript对象
2016/01/04 Javascript
JavaScript中的ajax功能的概念和示例详解
2016/10/17 Javascript
详解angular中通过$location获取路径(参数)的写法
2017/03/21 Javascript
JavaScript实现简单的双色球(实例讲解)
2017/07/31 Javascript
详解基于vue的移动web app页面缓存解决方案
2017/08/03 Javascript
Vue实现数据请求拦截
2019/10/23 Javascript
python实现排序算法
2014/02/14 Python
Python常用随机数与随机字符串方法实例
2015/04/09 Python
Python 3中的yield from语法详解
2017/01/18 Python
Python实现动态加载模块、类、函数的方法分析
2017/07/18 Python
利用Django模版生成树状结构实例代码
2019/05/19 Python
创建Django项目图文实例详解
2019/06/06 Python
python输出数组中指定元素的所有索引示例
2019/12/06 Python
Python中三维坐标空间绘制的实现
2020/09/22 Python
BeautifulSoup获取指定class样式的div的实现
2020/12/07 Python
利用css3 translate完美实现表头固定效果
2017/02/28 HTML / CSS
米兰必去买手店排行榜首位:Antonioli
2016/09/11 全球购物
Footshop法国:购买运动鞋
2020/01/19 全球购物
高中毕业自我鉴定
2013/12/19 职场文书
医院总经理职责
2013/12/26 职场文书
个人求职信范文分享
2014/01/31 职场文书
蜜蜂引路教学反思
2014/02/04 职场文书
2014全国两会学习心得体会2000字
2014/03/10 职场文书
小学生国庆演讲稿
2014/09/05 职场文书
综合素质评价自我评价
2015/03/06 职场文书
陶瓷类经典广告语集锦
2019/10/25 职场文书
python自然语言处理之字典树知识总结
2021/04/25 Python
Pytorch中Softmax与LogSigmoid的对比分析
2021/06/05 Python
一行Python命令实现批量加水印
2022/04/07 Python