整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:

Python 模块介绍之calendar

Python 模块介绍之calendar

alendar 是与日历相关的模块,该模块定义了很多类型,主要包括:Calendar、TextCalendar、HTMLCalendar,其中 Calendar 是 TextCalendar 和 HTMLCalendar 的基类,这些类有着十分丰富的日历处理方法。

calendar 模块

对于简单的文本日历,我们使用 calendar 模块直接调用的方法或属性即可,下面来具体看一下。

setfirstweekday(firstweekday)

设置每一周的开始(0 表示星期一,6 表示星期天),calendar 提供了 MONDAY、TUESDAY、WEDNESDAY、THURSDAY、FRIDAY、SATURDAY 和 SUNDAY 几个常量方便使用。例如,设置每周的第一天为星期天,示例如下:

import calendar
calendar.setfirstweekday(calendar.SUNDAY)

firstweekday()

返回当前设置的每星期的第一天的数值,默认为星期一。示例如下:

import calendar
print(calendar.firstweekday())

isleap(year)

如果 year 是闰年则返回 True,否则返回 False。示例如下:

import calendar
print(calendar.isleap(9102))

leapdays(y1, y2)

返回在范围 y1 至 y2 (包含 y1 和 y2 )之间的闰年的年数,其中 y1 和 y2 是年份。示例如下:

import calendar
print(calendar.leapdays(1945,2019))

weekday(year, month, day)

返回一周中的某一天 ( 0 ~ 6 代表周一至周日)。示例如下:

import calendar
print(calendar.weekday(2019,10,1))

monthrange(year, month)

返回指定年、月份第一天是星期几和这个月的天数。示例如下:

import calendar
print(calendar.monthrange(2019, 10))

monthcalendar(year, month)

返回表示一个月的日历的矩阵,每一行代表一周,此月份外的日子由零表示,每周默认从周一开始,可使用 setfirstweekday() 改变默认值。示例如下:

import calendar
print(calendar.monthcalendar(2019,10))

prmonth(theyear, themonth, w=0, l=0)

打印由 month() 返回的一个月的日历,每日宽度间隔为 w 字符,l 是每星期的行数。示例如下:

import calendar
print(calendar.prmonth(2019,10))

prcal(year, w=0, l=0, c=6, m=3)

打印由 calendar() 返回的整年的日历。示例如下:

import calendar
print(calendar.prcal(2019))

day_name

在当前的语言环境下表示星期几的列表。示例如下:

import calendar
print(calendar.day_name[0])

day_abbr

在当前语言环境下表示星期几缩写的列表。示例如下:

import calendar
print(calendar.day_abbr[0])

month_name

在当前语言环境下表示一年中月份的列表,一月的月号为 1,它的长度为 13 且 month_name[0] 是空字符串。示例如下:

import calendar
print(calendar.month_name[1])

month_abbr

在当前语言环境下表示月份简写的列表。示例如下:

import calendar
print(calendar.month_abbr[1])

Calendar 类

Calendar 对象提供了一些可被用于准备日历数据格式化的方法,这个类本身不执行任何格式化操作,这部分任务应由子类来完成,下面具体看一下。

iterweekdays()

返回一个迭代器,迭代器的内容为一星期的数字。示例如下:

from calendar import Calendar
c=Calendar()
print(list(c.iterweekdays()))

itermonthdates(year, month)

返回一个迭代器,迭代器的内容为 year 年 month 月(1-12)的日期。示例如下:

from calendar import Calendar
c=Calendar()
print(list(c.itermonthdates(2019,10)))

itermonthdays2(year, month)

返回一个迭代器,迭代器的内容与 itermonthdates() 类似为 year 年 month 月的日期,但不受 datetime.date 范围的限制,迭代器中的元素为一个由日期和代表星期几的数字组成的的元组。示例如下:

from calendar import Calendar
c=Calendar()
print(list(c.itermonthdays2(2019,10)))

itermonthdays3(year, month)

返回一个迭代器,迭代器的内容与 itermonthdates() 类似为 year 年 month 月的日期,不受 datetime.date 范围的限制,迭代器的元素为一个由年、月、日组成的元组。示例如下:

from calendar import Calendar
c=Calendar()
print(list(c.itermonthdays3(2019,10)))

TextCalendar 类

TextCalendar 对象提供了一些生成纯文本日历的方法,下面具体看一下。

formatmonth(theyear, themonth, w=0, l=0)

返回一个多行字符串来表示指定年月的日历,w 为日期的宽度,始终保持日期居中,l 指定了每星期占用的行数;以上这些还依赖于构造器或者 setfirstweekday() 方法指定的周的第一天是哪一天。示例如下:

from calendar import TextCalendar
tc=TextCalendar()
print(tc.formatmonth(2019,10))

prmonth(theyear, themonth, w=0, l=0)

与 formatmonth() 方法一样,返回一个月的日历。示例如下:

from calendar import TextCalendar
tc=TextCalendar()
print(tc.prmonth(2019,10))

formatyear(theyear, w=2, l=1, c=6, m=3)

返回一个多行字符串,这个字符串为一个 m 列日历,可选参数 w、l、c 分别表示日期列数、周的行数、月之间的间隔;以上这些还依赖于构造器或者 setfirstweekday() 指定哪一天为一周的第一天。示例如下:

from calendar import TextCalendar
tc=TextCalendar()
print(tc.formatyear(2019))

pryear(theyear, w=0, l=0, c=6, m=3)

与 formatyear() 方法一样,返回一整年的日历。示例如下:

from calendar import TextCalendar
tc=TextCalendar()
print(tc.pryear(2019))

HTMLCalendar 类

HTMLCalendar 对象提供了一些生成 HTML 日历的方法,下面具体看一下。

formatmonth(theyear, themonth, withyear=True)

返回一个 HTML 表格作为指定年月的日历,withyear 为 True,则年份将会包含在表头,否则只显示月份。示例如下:

from calendar import HTMLCalendar
hc=HTMLCalendar()
print(hc.formatmonth(2019,10))

formatyear(theyear, width=3)

返回一个 HTML 表格作为指定年份的日历,width 用于规定每一行显示月份的数量。示例如下:

from calendar import HTMLCalendar
hc=HTMLCalendar()
print(hc.formatyear(2019))

formatyearpage(theyear, width=3, css=’calendar.css’, encoding=None)

返回一个完整的 HTML 页面作为指定年份的日历,width 用于规定每一行显示的月份数量,css 为层叠样式表的名字,如果不使用任何层叠样式表,可以使用 None,encoding 为输出页面的编码 (默认为系统的默认编码)。示例如下:

家好,很高兴又见面了,我是"高级前端进阶",由我带着大家一起关注前端前沿、深入前端底层技术,大家一起进步,也欢迎大家关注、点赞、收藏、转发!

1.什么是 FullCalendar

FullCalendar 是一个用于创建日历界面的 JavaScript 开源库,支持全尺寸拖放(Full-sized drag & drop),同时具有适用于 React 和许多其他框架的适配器,比如:React、Vue、Angular 、Web Component等以及一流的 TypeScript 支持。

FullCalendar 目前非常受欢迎 ,除了易于使用之外还具有许多内置功能和用于充分定制的插件,而官方提供的插件数量已经达到了 25+。

目前 FullCalendar 在 Github 上通过 MIT 协议开源,有超过 17.3k 的 star、3.6k 的 fork、项目依赖量 63.8k、代码贡献者 100+、妥妥的前端优质开源项目。

2.为什么要 FullCalendar

2.1 不同视图支持

FullCalendar 库提供各种日历视图,例如:每月、每周和每天,还具有 TimeGrid 、 DayGrid 、TimeLine、Multi-Month Stack 等等视图模式,同时允许自定义视图,非常适合构建日程安排界面。

比如下面的代码设置了视图模式为 dayGridMonth:

import { Calendar } from '@fullcalendar/core';
import dayGridPlugin from '@fullcalendar/daygrid';

const calendar=new Calendar(calendarEl, {
  plugins: [dayGridPlugin],
  initialView: 'dayGridMonth',
});

页面渲染视图如下:

2.2 丰富的插件系统

FullCalendar 具有多种用于添加额外功能的插件。

插件系统很有用,因为开发者不需要下载整个代码库,但可以选择要包含的插件。 这样做可以缩小代码库的大小,并使管理依赖项变得更容易。

一些主流的插件包括:

  • @fullcalendar/interaction:提供点击、触摸、拖动交互。
  • @fullcalendar/daygrid:提供每月、每日和每周的日历视图。
  • @fullcalendar/timegrid:提供时间网格视图。
  • @fullcalendar/list:提供简化的列表视图。
  • @fullcalendar/vue3:支持 Vue3
  • @fullcalendar/vue:支持 Vue2
  • @fullcalendar/angular:支持 Angular 组件
  • @fullcalendar/react:支持 React 组件

下面是在 Vue3 中使用 FullCalendar 的代码示例:

<script>
import FullCalendar from '@fullcalendar/vue3'
import dayGridPlugin from '@fullcalendar/daygrid'
import interactionPlugin from '@fullcalendar/interaction'
export default {
  components: {
    FullCalendar
     // make the <FullCalendar> tag available
  },
  data() {
    return {
      calendarOptions: {
        plugins: [ dayGridPlugin, interactionPlugin ],
        initialView: 'dayGridMonth'
      }
    }
  }
}
</script>
<template>
  <FullCalendar :options="calendarOptions" />
</template>

3.使用 FullCalendar

3.1 基础用法

首先,需要安装核心 npm 包:

yarn add @fullcalendar/daygrid @fullcalendar/react

接下来,添加 FullCalendar 组件并包含日期网格插件:

import FullCalendar from '@fullcalendar/react';
import daygridPlugin from '@fullcalendar/daygrid';

export const MyCalendar=()=> {
  return (
    <div>
      <FullCalendar plugins={[daygridPlugin]} />
    </div>
  );
};

下面是设置以后的基础视图:

接下来可以自定义顶部工具栏并添加每周和每日视图。 FullCalendar 提供了 headerToolbar 属性,开发者可以使用它来选择想要查看的控件:

<FullCalendar
  headerToolbar={{
    start: 'today prev next',
    end: 'dayGridMonth dayGridWeek dayGridDay',
  }}
  plugins={[daygridPlugin]}
  views={['dayGridMonth', 'dayGridWeek', 'dayGridDay']}
/>

headerToolbar 对象接受 start, center、end 字段 , 每个字段都必须是可以包含标题、上一个、下一个、上一年、下一年、今天和日历视图名称(如 dayGridMonth)的字符串。

开发者可以按照想要的任何顺序排列这些字段,FullCalendar 将正确的渲染。

3.2 添加事件交互

为了给日历组件添加交互,需要首先添加 @fullcalendar/interaction 插件:

yarn add @fullcalendar/interaction

同时需要将 editable 和 selectable 属性设置为 true 并将事件处理程序放置在 events 属性中。

import FullCalendar from '@fullcalendar/react';
import daygridPlugin from '@fullcalendar/daygrid';
import interactionPlugin from '@fullcalendar/interaction';
import { useState } from 'react';
import { v4 as uuid } from 'uuid';

export const MyCalendar=()=> {
  const [events, setEvents]=useState([]);

  const handleSelect=(info)=> {
    const { start, end }=info;
    const eventNamePrompt=prompt('Enter, event name');
    if (eventNamePrompt) {
      setEvents([
        ...events,
        {
          start,
          end,
          title: eventNamePrompt,
          id: uuid(),
        },
      ]);
    }
  };

  return (
    <div>
      <FullCalendar
        editable
        selectable
        events={events}
        // 事件处理
        select={handleSelect}
        headerToolbar={{
          start: 'today prev next',
          end: 'dayGridMonth dayGridWeek dayGridDay',
        }}
        plugins={[daygridPlugin, interactionPlugin]}
        views={['dayGridMonth', 'dayGridWeek', 'dayGridDay']}
      />
    </div>
  );
};

以上代码首先添加了一个 handleSelect 回调,其接受 info 对象作为参数,该对象包含有关用户选择日期的信息。

Prompt() 函数向用户询问事件标题并创建一个包含开始、结束、标题和 ID 的新事件。而 id 属性需要是唯一的字符串,而这里引入了 uuid 三方库。

要添加编辑事件,可以遵循与上面类似的模式,只需要使用 eventClick 属性,而拖放操作则可以使用 eventChange 。

参考资料

https://github.com/fullcalendar/fullcalendar

https://isamatov.com/react-fullcalendar-tutorial/

https://fullcalendar.io/docs/plugin-index

https://fullcalendar.io/docs/vue

https://medevel.com/os-js-calendar/

造项目

CodePen原项目Calendar

场景

自己写个聚合首页,方便自己统一管理常用的网页工具,参考的是Mac OS的仪表盘,如下:

虽然短时间没法做到这么精美,但是起码功能得差不多吧,时钟与天气都已经OK,在做日历的时候觉得比较麻烦,就去CodePen找找看,便有了如此。

源码迁移

CodePen上的原项目本身难度不高,繁琐在理清楚日历逻辑(原作者逻辑),以及将此作者项目中关于DOM的操作转换成vue的模板操作。

先看逻辑

  1. 本月1号之前有可能存在上个月的尾巴(假如我们需要将日历方格全部填满)
  2. 本月内容以及当天的样式
  3. 本月最后一天后,也有可能会有下个月的月头

分别对应了原项目中这三个函数,原作者也有注释:

lastDayOfLastMonth 上个月最后一天,这里应该是原作者命名问题,应该是lastDayOfPreviousMonth

firstDayOfMonth 本月第一天

lastDateOfMonth 本月最后一天

i 是本月第几天,走了一个do while循环

上面的意思就是第一天时候把上个月尾巴给加到表格标签里面(最后统一加)

上面特殊处理的今天,其他本月内容都是常规加入,可以从class上面区分看出来。

上面的意思就是当本月最后一天的时候,顺便把下个月的月头加进来。

漏了,每行的首尾控制

这里说一下,因为日历是从周日到周六为一行,所以作者这里判断方案是Sunday与Saturday。

上面这些就是核心代码,当然还有下个月与上个月切换,不过就是清空当前日历再来一次,这些看源码即可,没有太多逻辑问题。


转vue

转起来难度不是很大,更多的是思维变化。

原项目是直接操作DOM,我们这里通过数据操作模板(姑且区分下),所以需要构建一个对象来承接每个”天“。

我们申明一个日历数组,由于日历是由若干个星期组成,所以我们就命名为:weeks,然后每个”天“给对象,属性如下:

那么我们的”天“会有这几种情况:

  1. 常规天
  2. 今天
  3. 上月或下月的天

接下来,我们把原逻辑里面对应的html,换成weeks,tr换成week(每次新建一个空数组),在周日或者第一天时候把week置空,在周六或本月最后一天把week闭合并且让weeks来push一下week,循环走完,我们一个月的关于weeks、week以及”天“的处理就完成了。

核心逻辑如下:

注意跨年问题

最终效果


源码请直接看原作者项目,感谢阅读。