Skip to content

时间的操作

ECMAScript 中的 Date 类型是在早期 Java 中的 java.util.Date 类基础上构建的。为此,Date 类型使用自 UTC (Coordinated Universal Time,国际协调时间)1970 年 1 月 1 日午夜(零时)开始经过的毫秒数来保存日期。在使用这种数据存储格式的条件下,Date 类型保存的日期能够精确到 1970 年 1 月 1 日之前或之后的 285 616 年。

判断时间是否在今天以前

通过传入一个时间的字符串,返回该时间相对于当前时间的对比。

试一试

示例代码
js
/**
 *
 * @param {String} time '2023-06-06 12:00:00'
 */
const timeCompare = (time) => {
  const date1 = new Date(time.replace(/\-/g, '/'))
  const date2 = new Date()
  const num = 24 * 60 * 60 * 1000
  const cha = date2.getTime() - date1.getTime()
  if (cha > 0) {
    if (cha > num) {
      alert('不是今天的过去时间')
    } else if (date1.getDate() !== date2.getDate()) {
      alert('不是今天的过去时间')
    } else {
      alert('是今天里的过去时间')
    }
  } else if (cha < 0) {
    alert('是未来时间')
  } else {
    alert('是现在')
  }
}

日期格式化important

传入一个指定格式的字符串,和需要格式化的时间new Date()或者是时间字符串2023-06-06 18:00:00,返回对应的格式化后的时间字符串。

试一试

选择格式:

或者

输入格式:
选择/输入的格式:fmt = yyyy-MM-dd
格式化的结果:2025-04-21
示例代码
js
/**
 *
 * @param {String | Date} time '2023-06-06' | new Date()
 * @param {String} fmt 'yyyy-MM-dd hh:mm:ss'
 */
const format = function (time, fmt) {
  time = time || new Date()
  fmt = fmt || 'yyyy-MM-dd hh:mm:ss'
  const typeOfTime = Object.prototype.toString.call(time).slice(8, -1)
  let finalTime = time
  if (typeOfTime !== 'Date') {
    const transformT = new Date(time.replace(/\-/g, '/'))
    const strT = transformT.toString()
    if (strT.indexOf('Invalid Date') !== -1) {
      alert('请输入正确格式的时间')
      return
    }
    finalTime = transformT
  }
  const o = {
    'M+': finalTime.getMonth() + 1, // 月
    'd+': finalTime.getDate(), // 日
    'h+': finalTime.getHours(), // 时
    'm+': finalTime.getMinutes(), // 分
    's+': finalTime.getSeconds(), // 秒
    'q+': Math.floor((finalTime.getMonth() + 3) / 3), // 季度
    S: finalTime.getMilliseconds(), // 毫秒
  }
  const a = /(y+)/.exec(fmt)
  if (a && a[0]) {
    fmt = fmt.replace(a[0], (finalTime.getFullYear() + '').substring(4 - a[0].length))
  }
  for (let k in o) {
    const b = new RegExp('(' + k + ')').exec(fmt)
    if (b && b[0]) {
      fmt = fmt.replace(b[0], b[0].length === 1 ? o[k] : ('00' + o[k]).substring(('' + o[k]).length))
    }
  }
  return fmt
}

获取不同时区的时间

getTimezoneOffset()返回本地时间与 UTC 时间相差的分钟数。列如,中国标准时间返回-480。

试一试

选中时区的时间:2025-04-21 11:04:46

示例代码
js
/**
 *
 * @param {Number} i 时区,例如东八区 i = 8;西八区 i = -8
 */
const getLocalTime = (i) => {
  const now = new Date()
  const time = now.getTime()
  const offset = now.getTimezoneOffset() * 60 * 1000 // 本地时间与UTC时间的偏移差(单位:ms)
  const utcTime = time + offset // 得到现在的UTC时间,各时区UTC时间相同
  return new Date(utcTime + 60 * 60 * 1000 * i) // 得到时区标准时间
}

获取指定结束时间的倒计时

给定一个结束时间的字符串,例如:2023-06-07 12:00:00。开启当前时间到结束时间的倒计时。

试一试

选择的结束日期:

倒计时:

示例代码
js
/**
 *
 * @param {String} endTime 结束日期:2023-06-07 12:00:00
 */
const getEndTime = (endTime) => {
  let startDate = new Date() //开始时间,当前时间
  let endDate = new Date(endTime.replace(/\-/g, '/')) //结束时间,需传入时间参数
  let t = endDate.getTime() - startDate.getTime() //时间差的毫秒数
  let d = 0,
    h = 0,
    m = 0,
    s = 0
  if (t >= 0) {
    d = Math.floor(t / 1000 / 3600 / 24)
    h = Math.floor((t / 1000 / 60 / 60) % 24)
    m = Math.floor((t / 1000 / 60) % 60)
    s = Math.floor((t / 1000) % 60)
  }
  return `${d}天${h}小时${m}分钟${s}秒`
}

验证码倒计时

试一试

获取验证码
示例代码
js
const sendCode = () => {
  if (sendStatus.disable) return
  let times = 60
  let timer = null
  timer = setInterval(() => {
    times--
    if (times <= 0) {
      sendStatus.text = '发送验证码'
      clearInterval(timer)
      sendStatus.disable = false
      times = 60
    } else {
      sendStatus.text = times + '秒后重试'
      sendStatus.disable = true
    }
  }, 1000)
}

实现一个日历

根据选择的年份和月份,显示出该月份的日历。

试一试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

选择的日期:2025年4月21日

示例代码
  1. 定义 select 选择器,选择年份和月份。以及日历元素。
html
<div class="content">
  <div class="selectWrap">
    <div class="selectItem">
      <label class="label">选择年份:</label>
      <select class="year" v-model="selectYear">
        <option v-for="option in years" :value="option">
          <p>{{ option }}</p>
        </option>
      </select>
    </div>
    <div class="selectItem">
      <label class="label">选择月份:</label>
      <select class="month" v-model="selectMonth">
        <option v-for="option in months" :value="option">
          <p>{{ option }}</p>
        </option>
      </select>
    </div>
  </div>
  <div class="calendarWrap">
    <div class="calendarCell title" v-for="week in weeks">{{ week }}</div>
    <div class="calendarCell" :class="[item.select ? 'select' : '', item.text === '' ? 'cannotSelect' : '', item.isToday ? item.select ? 'todaySelect' : 'isToday' : '']" v-for="item in calendar" @click="chooseCalendar(item)">{{ item.text }}</div>
  </div>
  <p><span>选择的日期是:</span>{{ choosedDate }}</p>
  <span class="today" v-show="showToday" @click="backToToday">今</span>
</div>
  1. 编写逻辑

核心 getMothDays() 方法返回一个数组,包含选中月份的所有天数以及占位符。
days 获取的是选中月份总共有多少天。
week 获取的是选中月份第一天是周几,用于确定第一天之前有几个占位符。

js
import { ref, reactive, watch } from 'vue'
const now = new Date()
const nowYear = now.getFullYear()
const nowMonth = now.getMonth() + 1
const day = now.getDate()
const years = reactive([2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021, 2022, 2023, 2024, 2025])
const months = reactive([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12])
const weeks = reactive(['日', '一', '二', '三', '四', '五', '六'])
const selectYear = ref(nowYear)
const selectMonth = ref(nowMonth)
const calendar = ref([])
const choosedDate = ref(`${selectYear.value}年${selectMonth.value}月${day}日`)
const showToday = ref(true)
const getMothDays = (year, month) => {
  let result = []
  const days = new Date(year, month, 0).getDate() 
  const week = new Date(`${year}/${month}/1`).getDay() 
  for (let i = 0; i < week; i++) {
    result.push({
      text: '',
      select: false,
    })
  }
  for (let i = 1; i <= days; i++) {
    result.push({
      text: i,
      select: i === day,
      isToday: i === day && selectYear.value === nowYear && selectMonth.value === nowMonth,
    })
  }
  calendar.value = result
  choosedDate.value = `${selectYear.value}年${selectMonth.value}月${day}日`
}
const chooseCalendar = (item) => {
  if (item.text === '') return
  calendar.value.forEach((i) => {
    i.select = false
  })
  item.select = !item.select
  choosedDate.value = `${selectYear.value}年${selectMonth.value}月${item.text}日`
}
const backToToday = () => {
  selectYear.value = nowYear
  selectMonth.value = nowMonth
  getMothDays(nowYear, nowMonth)
}
watch(
  [selectYear, selectMonth],
  ([year, month]) => {
    getMothDays(year, month)
  },
  {
    immediate: true,
  }
)
watch(
  choosedDate,
  (val) => {
    const str = val.replace(/[\u4E00-\u9FA5]+/g, '-')
    const arr = str.split('-')
    const year = nowYear
    const month = nowMonth
    console.log(year, month, day)
    if (year === +arr[0] && month === +arr[1] && day === +arr[2]) {
      showToday.value = false
    } else {
      showToday.value = true
    }
  },
  {
    immediate: true,
  }
)
  1. 应用样式
scss
.content {
  position: relative;
  .selectWrap {
    display: flex;
    align-items: center;
    font-size: 14px;
    .selectItem {
      margin-right: 20px;
      .label {
        margin-right: 5px;
      }
      .year {
        width: 100px;
      }
      .month {
        width: 50px;
      }
    }
  }
  .calendarWrap {
    width: 400px;
    display: grid;
    grid-template-columns: repeat(7, 1fr);
    gap: 0 5px;
    border: 1px solid #ccc;
    border-radius: 8px;
    margin: 10px 0;
    padding: 10px;
    background: #fff;
    .calendarCell {
      width: 50px;
      height: 50px;
      border-radius: 50%;
      line-height: 50px;
      text-align: center;
      cursor: pointer;
      &.title {
        cursor: auto;
      }
      &.select {
        background: rgba(0, 0, 0, 0.1);
      }
      &.todaySelect {
        background: #10b981;
        color: #fff;
      }
      &.isToday {
        background: #fff;
        color: #10b981;
      }
      &.cannotSelect {
        cursor: not-allowed;
      }
    }
  }
  .today {
    position: absolute;
    top: -25px;
    left: 330px;
    display: inline-block;
    width: 50px;
    height: 50px;
    line-height: 50px;
    text-align: center;
    border-radius: 50%;
    background: #10b981;
    color: #fff;
    cursor: pointer;
  }
}