You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

94 lines
2.8 KiB

  1. """Translate an ics file's events to a different timezone."""
  2. from datetime import datetime
  3. from optparse import OptionParser
  4. import pytz
  5. from dateutil import tz
  6. import vobject
  7. version = "0.1"
  8. def change_tz(cal, new_timezone, default, utc_only=False, utc_tz=vobject.icalendar.utc):
  9. """
  10. Change the timezone of the specified component.
  11. Args:
  12. cal (Component): the component to change
  13. new_timezone (tzinfo): the timezone to change to
  14. default (tzinfo): a timezone to assume if the dtstart or dtend in cal doesn't have an existing timezone
  15. utc_only (bool): only convert dates that are in utc
  16. utc_tz (tzinfo): the tzinfo to compare to for UTC when processing utc_only=True
  17. """
  18. for vevent in getattr(cal, 'vevent_list', []):
  19. start = getattr(vevent, 'dtstart', None)
  20. end = getattr(vevent, 'dtend', None)
  21. for node in (start, end):
  22. if node:
  23. dt = node.value
  24. if isinstance(dt, datetime) and (not utc_only or dt.tzinfo == utc_tz):
  25. if dt.tzinfo is None:
  26. dt = dt.replace(tzinfo=default)
  27. node.value = dt.astimezone(new_timezone)
  28. def show_timezones():
  29. for tz_string in pytz.all_timezones:
  30. print(tz_string)
  31. def convert_events(utc_only, args):
  32. print("Converting {} events".format('only UTC' if utc_only else 'all'))
  33. ics_file = args[0]
  34. _tzone = args[1] if len(args) > 1 else 'UTC'
  35. print("... Reading {}".format(ics_file))
  36. cal = vobject.readOne(open(ics_file))
  37. change_tz(cal, new_timezone=tz.gettz(_tzone), default=tz.gettz('UTC'), utc_only=utc_only)
  38. out_name = "{}.converted".format(ics_file)
  39. print("... Writing {}".format(out_name))
  40. with open(out_name, 'wb') as out:
  41. cal.serialize(out)
  42. print("Done")
  43. def main():
  44. options, args = get_options()
  45. if options.list:
  46. show_timezones()
  47. elif args:
  48. convert_events(utc_only=options.utc, args=args)
  49. def get_options():
  50. # Configuration options
  51. usage = """usage: %prog [options] ics_file [timezone]"""
  52. parser = OptionParser(usage=usage, version=vobject.VERSION)
  53. parser.set_description("change_tz will convert the timezones in an ics file. ")
  54. parser.add_option("-u", "--only-utc", dest="utc", action="store_true",
  55. default=False, help="Only change UTC events.")
  56. parser.add_option("-l", "--list", dest="list", action="store_true",
  57. default=False, help="List available timezones")
  58. (cmdline_options, args) = parser.parse_args()
  59. if not (args or cmdline_options.list):
  60. print("error: too few arguments given")
  61. print(parser.format_help())
  62. return cmdline_options, False
  63. return cmdline_options, args
  64. if __name__ == "__main__":
  65. try:
  66. main()
  67. except KeyboardInterrupt:
  68. print("Aborted")