详解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 相关文章推荐
一个简单的javascript类定义例子
Sep 12 Javascript
jquery 经典动画菜单效果代码
Jan 26 Javascript
js 自制滚动条的小例子
Mar 16 Javascript
jquery获取URL中参数解决中文乱码问题的两种方法
Dec 18 Javascript
PHP中使用微秒计算脚本执行时间例子
Nov 19 Javascript
jQuery插件jRumble实现网页元素抖动
Jun 05 Javascript
JS读写CSS样式的方法汇总
Aug 16 Javascript
JavaScript学习笔记--常用的互动方法
Dec 07 Javascript
js定时器实例分享
Dec 20 Javascript
jquery插件treegrid树状表格的使用方法详解(.Net平台)
Jan 03 Javascript
jquery轮播图插件使用方法详解
Jul 31 jQuery
JavaScript arguments.callee作用及替换方案详解
Sep 02 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 chr() ord()中文截取乱码问题解决方法
2008/09/08 PHP
php常用的url处理函数总结
2014/11/19 PHP
PHP中实现Bloom Filter算法
2015/03/30 PHP
XHTML下,JS浮动代码失效的问题
2009/11/12 Javascript
iframe子父页面调用js函数示例
2013/11/07 Javascript
js 数组去重的四种实用方法
2014/09/09 Javascript
轻松学习Javascript闭包函数
2015/12/15 Javascript
用JavaScript实现让浏览器停止载入页面的方法
2017/01/19 Javascript
微信小程序实战之轮播图(3)
2017/04/17 Javascript
angular.js指令中的controller、compile与link函数的不同之处
2017/05/10 Javascript
vue params、query传参使用详解
2017/09/12 Javascript
解决Webpack 热部署检测不到文件变化的问题
2018/02/22 Javascript
vue-cli开发环境实现跨域请求的方法
2018/04/07 Javascript
详解Vue前端生产环境发布配置实战篇
2019/05/07 Javascript
layui表格分页 记录勾选的实例
2019/09/02 Javascript
javascript/jquery实现点击触发事件的方法分析
2019/11/11 jQuery
解决三元运算符 报错“SyntaxError: can''t assign to conditional expression”
2020/02/12 Javascript
Python 返回汉字的汉语拼音
2009/02/27 Python
Linux下多个Python版本安装教程
2018/08/15 Python
Tensorflow实现多GPU并行方式
2020/02/03 Python
在 Python 中接管键盘中断信号的实现方法
2020/02/04 Python
Python使用sqlite3模块内置数据库
2020/05/07 Python
python初步实现word2vec操作
2020/06/09 Python
安装python3.7编译器后如何正确安装opnecv的方法详解
2020/06/16 Python
image-set实现Retina屏幕下图片显示详细介绍
2012/12/24 HTML / CSS
美国玩具公司:U.S.Toy
2018/05/19 全球购物
Carmen Sol官网:购买果冻鞋、手袋和配件
2021/01/01 全球购物
一月红领巾广播稿
2014/02/11 职场文书
热爱祖国演讲稿
2014/05/04 职场文书
减负增效提质方案
2014/05/23 职场文书
八项规定自查自纠报告及整改措施
2014/10/26 职场文书
信用卡收入证明范本
2015/06/12 职场文书
催款函怎么写
2015/06/24 职场文书
小学体育组工作总结
2015/08/13 职场文书
2019班干部竞选演讲稿范本!
2019/07/08 职场文书
《黑岩★★射手 DAWN FALL》BD发售宣传CM公开
2022/04/04 日漫