SHELL命令-常用的日期函数


一.SHELL常用的日期函数

1.时间部分

%  : 打印出% 
%n : 下一行
%t : 跳格
%H : 小时(00..23)
%I : 小时(01..12)
%k : 小时(0..23)
%l : 小时(1..12)
%M : 分钟(00..59)
%p : 显示本地 AM 或 PM
%r : 直接显示时间 (12 小时制,格式为 hh:mm:ss [AP]M)
%s : 从 1970 年 1 月 1 日 00:00:00 UTC 到目前为止的秒数 %S : 秒(00..61)
%T : 直接显示时间 (24 小时制)
%X : 相当于 %H:%M:%S
%Z : 显示时区

2.日期部分

%a : 星期几 (Sun..Sat)
%A : 星期几 (Sunday..Saturday)
%b : 月份 (Jan..Dec)
%B : 月份 (January..December)
%c : 直接显示日期和时间
%d : 日 (01..31)
%D : 直接显示日期 (mm/dd/yy)
%F : 日期格式%Y-%m-%d
%h : 同 %b
%j : 一年中的第几天 (001..366)
%m : 月份 (01..12)
%U : 一年中的第几周 (00..53) (以 Sunday 为一周的第一天的情形)
%w : 一周中的第几天 (0..6)
%W : 一年中的第几周 (00..53) (以 Monday 为一周的第一天的情形)
%x : 直接显示日期 (mm/dd/yy)
%y : 年份的最后两位数字 (00.99)
%Y : 完整年份 (0000..9999)

3.使用命令

3.1.格式

date [OPTION][+FORMAT]

3.2.举个栗子

获取今天日期:

date "+%Y-%m %s"
date "+%F"
date "+%F %X"
date "+%F %T"

3.3.特别注意

Mac下的date命令是BSD(Berkeley Software Distribution)系的,Linux下date命令是GNU(GNU’s Not Unix)系,二者用法有一些区别.
BSD并不特指任何一个BSD衍生版本,而是类UNIX操作系统中的一个分支的总称.
Mac OS X和iOS实际上基于Darwin,Darwin是BSD其中一个分支.

获取前一天和获取后一天的写法不同:

  • Mac,通过-v参数,-v-1d代表前一天,-v-1y代表上一年
  • Linux,通过--date/-d参数实现,--date='-1 day'/-d '-1 day'代表前一天,--date='-1 year'代表上一年
# macos
date -v-1d +%F
# linux
date -d "-1 day" "+%F"

4.常用指令

一般服务器都是linux内核,macos不同的地方这里省略.

4.1.next/last

date -d 'next monday' +%Y%m%d # 下周一的日期
date -d 'next-day' +%Y%m%d # 明天的日期 或者:date -d tomorrow +%Y%m%d
date -d 'last-day' +%Y%m%d # 昨天的日期 或者:date -d yesterday +%Y%m%d
date -d 'last-month' +%Y%m # 上个月是几月
date -d 'next-month' +%Y%m # 下个月是几月

4.2.ago(seconds/hours/days/weeks/months/years)

date -d '30 days ago' # 30天前的日期
date -d 'dec 14 -2 weeks' # 相对:dec 14这个日期的两周前的日期
date -d '-100 days' # 100天以前的日期
date -d '50 days' # 50天后的日期

二.数仓中常用的自定义日期函数

1.自定义函数(DateUtils.sh)

#!/bin/sh

# Copyright (c) 2018 codingstandards. All rights reserved.
# file: DateUtils.sh
# description: Bash中关于日期的常用自定义函数
# license: LGPL
# author: darebeat
# email: darebeat@126.com
# version: 1.0
# date: 2018.08.28

#判断是否闰年 
#input:year 
#output: "true" "fase" 
is_leap() {
    Y=`expr substr $1 1 4`
    r1=`expr $Y % 4`
    r2=`expr $Y % 100`
    r3=`expr $Y % 400`
    if [ $r1 -eq 0 -a $r2 -ne 0 -o $r3 -eq 0 ]; then
      FRUN="true"
    else
      FRUN="false"
    fi
    echo $FRUN
}

# 日期前一天,默认是当前日期
# 比如今天是2018年8月28日,那么结果就是2018-08-27
# usage:
# yesterday 20180828 %Y-%m-%d
# yesterday 20180828
yesterday() {
  date -d "$1 1 day ago" "+${2:-%Y%m%d}"
}

# 日期所在的日期
curr_day() {
  date -d "$1" "+${2:-%Y%m%d}"
}

# 日期所在周的第一天的日期
# usage:
# curr_week_first_day 20180828 %Y-%m-%d
# curr_week_first_day 20180828
curr_week_first_day() {
  tmp_wd=$(date -d "$1" "+%w")
  if [[ $tmp_wd == '0' ]]; then
    tmp_wd='7'
  fi
  date -d "$(date -d "$1 -$tmp_wd day" "+${2:-%Y%m%d}") 1 day" "+${2:-%Y%m%d}"
}

# 日期环比上周的日期
# usage:
# wow_week_day 20180828 %Y-%m-%d
# wow_week_day 20180828
wow_week_day() {
  date -d "$1 1 week ago" "+${2:-%Y%m%d}"
}

# 日期环比所在周的第一天的日期
# usage:
# wow_week_first_day 20180828 %Y-%m-%d
# wow_week_first_day 20180828
wow_week_first_day() {
  curr_week_first_day $(wow_week_day $1) ${2:-%Y%m%d}
}

# 日期所在月的第一天的日期
# usage:
# curr_month_first_day 20180828 %Y-%m-01
# curr_month_first_day 20180828
curr_month_first_day() {
  date -d "$1" "+${2:-%Y%m01}"
}

# 日期所在月的最后一天的日期
# usage:
# curr_month_last_day 20180828 %Y-%m-%d
# curr_month_last_day 20180828
curr_month_last_day() {
  yesterday $(date -d "$1 1 month" "+%Y%m01") ${2:-%Y%m%d}
}

# 日期环比月第一天所在的日期
# usage:
# mom_month_first_day 20180828 %Y-%m-01
# mom_month_first_day 20180828
mom_month_first_day() {
  date -d "$1 -1 month" "+${2:-%Y%m01}"
}

# 日期环比月所在的日期
# usage:
# mom_month_day 20180828 %Y-%m-%d
# mom_month_day 20180828
mom_month_day() {
  tmp_lm_last_day=$(date -d "$(curr_month_last_day $(mom_month_first_day $1))" "+%e")
  tmp_curr_last_day=$(date -d "$(curr_month_last_day $1)" "+%e")
  tmp_curr_day=$(date -d "$1" "+%e")

  if [[ ${tmp_lm_last_day} -lt ${tmp_curr_last_day} && ${tmp_curr_day} -ge ${tmp_lm_last_day} ]]; then
    curr_month_last_day $(mom_month_first_day $1)
  elif [[ ${tmp_lm_last_day} -ge ${tmp_curr_last_day} && ${tmp_curr_day} -ge ${tmp_curr_last_day} ]]; then
    curr_month_last_day $(mom_month_first_day $1)
  else
    date -d "$1 -1 month" "+${2:-%Y%m%d}"
  fi
}

# 日期同比月所在的日期
# usage:
# mym_month_day 20180828 %Y-%m-%d
# mym_month_day 20180828
mym_month_day() {
  date -d "$1 -1 year" "+${2:-%Y%m%d}"
}

# 日期同比月第一天所在的日期
# usage:
# mym_month_first_day 20180828 %Y-%m-01
# mym_month_first_day 20180828
mym_month_first_day() {
  date -d "$1 -1 year" "+${2:-%Y%m01}"
}

2.测试和使用案例

#!/usr/bin/env bash

declare -r CURR_DIR=$(cd `dirname $0`; pwd)

source ${CURR_DIR}/DateUtils.sh

test_date=20180328
echo $test_date

echo "获取日期的前一天的日期"
yesterday $test_date %Y-%m-%d
yesterday $test_date

echo "日期所在月的第一天的日期"
curr_month_first_day $test_date %Y-%m-01
curr_month_first_day $test_date

echo "日期环比上周的日期"
wow_week_day $test_date %Y-%m-%d
wow_week_day $test_date

echo "日期所在周的第一天的日期"
curr_week_first_day $test_date %Y-%m-%d
curr_week_first_day $test_date

echo "日期环比所在周的第一天的日期"
wow_week_first_day $test_date %Y-%m-%d
wow_week_first_day $test_date

echo "日期所在月的最后一天的日期"
curr_month_last_day $test_date %Y-%m-%d
curr_month_last_day $test_date

echo "日期环比月所在的日期"
mom_month_day $test_date %Y-%m-%d
mom_month_day $test_date

echo "日期环比月第一天所在的日期"
mom_month_first_day $test_date %Y-%m-01
mom_month_first_day $test_date

echo "日期同比月所在的日期"
mym_month_day $test_date %Y-%m-%d
mym_month_day $test_date

echo "日期同比月第一天所在的日期"
mym_month_first_day $test_date %Y-%m-01
mym_month_first_day $test_date

文章作者: darebeat
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 darebeat !
 上一篇
记住这些,解决你80%以上MySQL查询优化的问题 记住这些,解决你80%以上MySQL查询优化的问题
在使用MySQL过程中,根据本文提供的原则和方法,避免一些容易导致SQL查询比较慢的场景。
2021-02-18
下一篇 
SQOOP原理和使用小记 SQOOP原理和使用小记
Sqoop是一个在结构化数据和Hadoop之间进行批量数据迁移的工具,结构化数据可以是MySQL、Oracle等RDBMS.Sqoop底层用MapReduce程序实现抽取、转换、加载,MapReduce天生的特性保证了并行化和高容错率,而且相比Kettle等传统ETL工具,任务跑在Hadoop集群上,减少了ETL服务器资源的使用情况。
2021-01-31
  目录