日历标准格式
概述
通用的日历格式是 iCalendar,通常扩展名是.ics
iCalendar允许用户通过电子邮件的方式发送“会议请求”或“任务”。收信人使用支持iCalendar邮件客户端,便可以很方便地回应发件人,接受请求或另外提议一个新的会议时间。
维基百科中关于 iCalendar 的描述是: https://zh.wikipedia.org/wiki/ICalendar
标准
具体参考的标准是 RFC 5545
一般 ics 文件的格式
BEGIN:VCALENDAR # 日历开始
PRODID:-//test.us//iCalendar Event//EN # 软件信息
VERSION:2.0 # 遵循的 iCalendar 版本号
CALSCALE:GREGORIAN # 历法:公历
METHOD:PUBLISH # 方法:公开 也可以是 REQUEST 等用于日历间的信息沟通方法
CLASS:PUBLIC # Classification 此属性定义日历组件的访问分类: "PUBLIC" / "PRIVATE" / "CONFIDENTIAL" / iana-token / x-name
BEGIN:VTIMEZONE # Time Zone Component
TZID:Asia/Shanghai # Time Zone Identifier 时区标识符
TZURL:http://tzurl.org/zoneinfo-outlook/Asia/Shanghai # Time Zone URL: 访问 http://tzurl.azureedge.net/zoneinfo-outlook/Asia
X-LIC-LOCATION:Asia/Shanghai
BEGIN:STANDARD
TZOFFSETFROM:+0800
TZOFFSETTO:+0800
TZNAME:CST
DTSTART:19700101T000000
END:STANDARD
END:VTIMEZONE # 时区组件结束
BEGIN:VEVENT # 事件开始
DTSTAMP:20190723T071307Z # 有 Method 属性时表示 实例创建时间,没有时表示最后修订的日期时间
DTSTART;TZID=Asia/Shanghai:20191024T150000 # 开始的日期时间
DTEND;TZID=Asia/Shanghai:20191024T160000 # 结束的日期时间
SUMMARY:我的会议 # 简介 一般是标题
# UID (唯一标识符)
UID:20190723T071307Z-105904298@fe80:0:0:0:e4:cbff:fe80:b24c%ens5
# Time Zone Identifier 时区标识符
TZID:Asia/Shanghai
# 描述
DESCRIPTION:issac 的描述
# 地址
LOCATION:https://cloud.tencent.com/developer/user/6258660
# Alarm Component 报警组件
BEGIN:VALARM
# 触发 alarm (开始之前10分钟提醒)
TRIGGER:-PT10M
# AUDIODISPLAYEMAIL
ACTION:DISPLAY
# In a DISPLAY alarm, the intended alarm effect is for
# the text value of the "DESCRIPTION" property to be displayed to the user.
DESCRIPTION:Reminder
# alarm 结束
END:VALARM
# 事件结束
END:VEVENT
# 日历结束
END:VCALENDAR
设置日历周期性重复
# 重复规则 rrule (Recurrence Rule):
RRULE:FREQ=WEEKLY;WKST=SU;UNTIL=20190917T133000;INTERVAL=1;BYDAY=TU
重复规则 rrule (Recurrence Rule)
重复规则包含多个属性, 每个属性以 NAME = VALUE 对的形式存在, 属性与属性之间用分号区分, 属性之间没有特定的顺序要求,在同一个重复规则中每个属性最多只能出现一次。
1、FREQ
FREQ 属性表示重复规则的类型,可选的 VALUE 有:
- SECONDLY, 表示以秒为间隔单位进行重复。
- MINUTELY, 表示以分钟为间隔单位进行重复。
- HOURLY, 表示以小时为间隔单位进行重复。
- DAILY, 表示以天为间隔单位进行重复。
- WEEKLY, 表示以周为间隔单位进行重复。
- MONTHLY, 表示以月为间隔单位进行重复。
- YEARLY, 表示以年为间隔单位进行重复。
2、WKST
WKST 取值范围 MO(周一), TU(周二), WE(周三), TU(周四), FR(周五), SA(周六), SU(周日)。 默认值为 MO。
当一个 WEEKLY 类型的重复规则, INTERVAL 大于 1, 且带有 BYDAY 属性时, 则必须带有 WKST 属性。 当一个 YEARLY 类型的重复规则带有 BYWEEKNO 属性时, 也必须带有 WKST 属性。
3、UNTIL
UNTIL 属性定义了一个日期-时间值,用以限制重复规则。
这个日期-时间值表示这个重复规则的最后一次事件的发生时间。
如果重复规则中未包含 UNTIL 和 COUNT 属性, 则表示该重复规则无限重复。
4、INTERVAL
INTERVAL 属性表示重复规则的间隔, 必须为正整数。 默认值为1。
对应上述不同的 FREQ 值分别表示每一秒,每一分钟, 每一小时, 每一天, 每一周, 每一月, 每一年。s
5、BYDAY
BYDAY 取值范围: MO(周一), TU(周二), WE(周三), TU(周四), FR(周五), SA(周六), SU(周日)。可以有多个值,用逗号分隔。
每个值可以在前面加上一个正整数(+n)或者负整数(-n),用以在 MONTHLY 或者 YEARLY 的重复类型中表示第 n 个周几。 例如,在一个 MONTHLY 类型的重复规则中, +1MO(或者1MO)表示这个月的第1个周一,如果是 -1MO 则表示这个月的最后1个周一。
如果前面没有数字,则表示在这个重复类型中的所有的周几, 比如在一个 MONTHLY 的重复类型中, MO 表示这个月里所有的周一。
与 Google 日历同步
调用 Google Calendar API 的 demo
#!/usr/bin/python
# -*- coding: UTF-8 -*-
import BaseHTTPServer
import httplib2
import urlparse
from apiclient.discovery import build
from oauth2client.client import OAuth2WebServerFlow
class RequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
"""Child class of BaseHTTPRequestHandler that only handles GET request."""
# https://developers.google.com/calendar/quickstart/js
clientID = '295995113385-nu8em9928itnt7fa92dc5ab1tv710ojs.apps.googleusercontent.com'
apiKey = 'YFzGsExw6fURfmysfxr1lvpF'
authUrl = 'https://www.googleapis.com/auth/calendar'
flow = OAuth2WebServerFlow(clientID, apiKey, authUrl, redirect_uri='http://localhost:8080/')
def do_GET(self):
"""Handler for GET request."""
print 'nnNEW REQUEST, Path: %s' % (self.path)
if self.path.startswith('/?fake_user='):
self.handle_initial_url()
# When you redirect to the authorization server below, it redirects back
# to to http://localhost:8080/?code=<some_code> after the user grants access
# permission for your application.
elif self.path.startswith('/?code='):
self.handle_redirected_url()
else:
self.respond_ignore() # Either an error from auth server or bad user entered URL.
def handle_initial_url(self):
"""Handles the initial path."""
parsed = urlparse.urlparse(self.path)
fake_user = urlparse.parse_qs(parsed.query)['fake_user'][0]
self.respond_redirect_to_auth_server(fake_user)
def respond_redirect_to_auth_server(self, fake_user):
"""Respond to the current request by redirecting to the auth server."""
uri = RequestHandler.flow.step1_get_authorize_url()
print 'Redirecting %s to %s' % (fake_user, uri)
self.send_response(301)
self.send_header('Cache-Control', 'no-cache')
self.send_header('Location', uri)
self.end_headers()
def handle_redirected_url(self):
"""Handles the redirection back from the authorization server."""
# The server should have responded with a "code" URL query parameter. This is needed to acquire credentials.
parsed = urlparse.urlparse(self.path)
code = urlparse.parse_qs(parsed.query)['code'][0]
credentials = RequestHandler.flow.step2_exchange(code)
http = httplib2.Http()
http = credentials.authorize(http)
service = build('calendar', 'v3', http=http)
event = {
# 'summary': 'Google I/O 2015',
'summary': 'tttttt',
'location': '800 Howard St., San Francisco, CA 94103',
'description': 'A chance to hear more about Google's developer products.',
'start': {
'dateTime': '2019-08-18T09:00:00-07:00',
'timeZone': 'America/Los_Angeles',
},
'end': {
'dateTime': '2019-08-18T17:00:00-07:00',
'timeZone': 'America/Los_Angeles',
},
'recurrence': [
# 'RRULE:FREQ=DAILY;COUNT=2'
# 'RRULE:FREQ=WEEKLY' # 每周重复
# 'RRULE:FREQ=WEEKLY;WKST=SU;UNTIL=20200121T133000;INTERVAL=4;BYDAY=TU' # 报错了
],
'attendees': [
{'email': 'lpage@example.com'},
{'email': 'sbrin@example.com'},
],
'reminders': {
'useDefault': False,
'overrides': [
# {'method': 'email', 'minutes': 24 * 60},
{'method': 'popup', 'minutes': 15},
],
},
}
res = service.events().insert(calendarId='primary', body=event).execute()
parsed = urlparse.urlparse(res.get('htmlLink'))
eidCode = urlparse.parse_qs(parsed.query)['eid'][0]
eventeditUrl = 'https://calendar.google.com/calendar/r/eventedit/' + eidCode
print '>>> eventeditUrl: %s' % (eventeditUrl)
self.send_response(301)
self.send_header('Cache-Control', 'no-cache')
self.send_header('Location', eventeditUrl)
self.end_headers()
def respond_ignore(self):
"""Responds to the current request that has an unknown path."""
self.send_response(200)
self.send_header('Content-type', 'text/plain')
self.send_header('Cache-Control', 'no-cache')
self.end_headers()
self.wfile.write(
'This path is invalid or user denied access:n%snn' % self.path)
self.wfile.write(
'User entered URL should look like: http://localhost:8080/?fake_user=johndoe')
def main():
try:
server = BaseHTTPServer.HTTPServer(('', 8080), RequestHandler)
print 'Starting server. Use Control+C to stop.'
server.serve_forever()
except KeyboardInterrupt:
print 'Shutting down server.'
server.socket.close()
if __name__ == '__main__':
main()
Google Calendar API 参考资料
- OAuth 认证
- Google Calendar API 开发示例
- Google Calendar API 文档
与 outlook 日历同步
the Outlook REST API
Outlook calendar API
Outlook 加载项
- java知识点归纳
- EaseMobile 主题导航菜单设置小图标的方法(图文+视频教程)
- NEC css规范
- DW Mobile Switcher:移动设备识别切换主题插件
- 揭秘技术大国以色列
- mix-blend-mode 混合模式 background-blend-mode 背景混合模式 isolation:isolate 隔离
- wp_nav_menu 函数经Walker_Nav_Menu 类自定义导航菜单HTML
- css3 RGBA 红色R+绿色G+蓝色B+Alpha通道
- css3 gradient 渐变
- TwentyTwenty:一个图片特效Jquery 插件
- 何为实在
- css3 动画应用 animations 和transtions transform在加上JavaScript 可以实现硬件加速动画。
- 善良比聪明更重要
- zepto 基础知识(6)
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 简易Ramdisk 镜像制作(基于Centos7+)
- 在 K8S 部署一个 Spark History Server - 篇1
- R语言入门之非参数假设检验
- 在 K8S 部署一个 Spark History Server - 篇2
- UEFI/LEGACY 可启动ISO制作
- Kerberized HDFS with Kubernetes
- 经典 | Python实例小挑战—Part nine
- Mac CPU 相关
- 经典 | Python实例小挑战—Part ten
- 查看 Linux CPU 信息
- 方差分析(ANOVA)
- ps 究竟是 aux 还是 ef
- R语言入门之数据的索引
- 【用SQLite做数据分析】Python操作SQLite的入门介绍
- Flink Session Cluster on K8S