prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  Importing a TTFont from XML fails when LC_TIME is set
  Importing a font from XML while LC_TIME locale is set to non-English, causes an error.
  
  ### How to reproduce?
  
  This might be easy when a non-English locale is available in the system. I came across this, while using a package on top. The corresponding issue in their package is amueller/word_cloud#530. There is a script to reproduce, which only throws an error, when a non-English locale like 'de_DE' is set with e. g. `locale.setlocale(locale.LC_TIME, 'de_DE.UTF-8')` or just by opening Spyder-IDE.
  
  **A simplified test is:**
  ```python
  import locale
  locale.setlocale(locale.LC_TIME, 'de_DE.UTF-8') # works if de_DE is available
  
  from fontTools.misc.timeTools import timestampFromString,timestampToString,timestampNow
  ts_now = timestampNow()
  str_now = timestampToString(ts_now)
  timestampFromString(str_now) # ValueError
  ```
  
  Let's go into the cause of the error.
  
  ### Basics
  
  The locale for LC_TIME can be checked with
  ```python
  import locale
  print(locale.getlocale(locale.LC_TIME))
  ```
  This outputs `('de_DE', 'UTF-8')` in my case.
  
  With this locale the following fails:
  ```python
  import time
  time.strptime('Mon', '%a')
  # ValueError: unconverted data remains: n
  ```
  `'Mo'` is the localized abbreviation in de_DE for Monday.
  
  ### TTFont
  
  The method [`importXML`](https://github.com/fonttools/fonttools/blob/master/Lib/fontTools/ttLib/ttFont.py#L318) in `TTFont` receives the font object as XML. This can contain created and modified dates. The XML is parsed by the `XMLReader`, which somehow uses the [`fromXML`](https://github.com/fonttools/fonttools/blob/master/Lib/fontTools/ttLib/tables/_h_e_a_d.py#L107) method in `table__h_e_a_d`. There the created and modified dates are parsed using [`timestampFromString`](https://github.com/fonttools/fonttools/blob/master/Lib/fontTools/misc/timeTools.py#L46) from timeTools. This helper function uses `time.strptime(value)`.
  
  In my test case `value` is initialized from the 'created' attribute of a font as `'Mon Jan 8 12:28:04 2007'`, which throws the following error:
  ```
  ValueError: time data 'Mon Jan  8 12:28:04 2007' does not match format '%a %b %d %H:%M:%S %Y'
  ```
  
  
  ### How to resolve?
  
  I think the parsing should be done without locale, since the XML attribute is likely to be non-local. In the opposite function [`timestampToString`](https://github.com/fonttools/fonttools/blob/master/Lib/fontTools/misc/timeTools.py#L43) `asctime` is used, which uses a fixed list of abbreviated week days and months. So that is not localized. Hence [`timestampFromString`](https://github.com/fonttools/fonttools/blob/master/Lib/fontTools/misc/timeTools.py#L46) shouldn't be localized as well.
  
  A simple solution could be
  ```python
  def timestampFromString(value):
  	import locale
  	l = locale.getlocale(locale.LC_TIME)
  	locale.setlocale(locale.LC_TIME, 'C')
  	try:
  		t = time.strptime(value)
  	finally:
  		locale.setlocale(locale.LC_TIME, l)
  	return calendar.timegm(t) - epoch_diff
  ```
  
  However, changing the locale is not recommended. It's better to use a function that can parse a date with specified locale without changing it. You could use [dateparser](https://dateparser.readthedocs.io/en/latest/) for example, but I don't know about your dependencies and how you handle it.
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  --- BEGIN FILES ---
  Path: `Lib/fontTools/misc/timeTools.py`
  Content:
  ```
  1 """fontTools.misc.timeTools.py -- tools for working with OpenType timestamps.
  2 """
  3 
  4 from fontTools.misc.py23 import *
  5 import os
  6 import time
  7 import calendar
  8 
  9 
  10 epoch_diff = calendar.timegm((1904, 1, 1, 0, 0, 0, 0, 0, 0))
  11 
  12 DAYNAMES = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"]
  13 MONTHNAMES = [None, "Jan", "Feb", "Mar", "Apr", "May", "Jun",
  14 			  "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
  15 
  16 
  17 def asctime(t=None):
  18 	"""
  19 	Convert a tuple or struct_time representing a time as returned by gmtime()
  20 	or localtime() to a 24-character string of the following form:
  21 
  22 	>>> asctime(time.gmtime(0))
  23 	'Thu Jan  1 00:00:00 1970'
  24 
  25 	If t is not provided, the current time as returned by localtime() is used.
  26 	Locale information is not used by asctime().
  27 
  28 	This is meant to normalise the output of the built-in time.asctime() across
  29 	different platforms and Python versions.
  30 	In Python 3.x, the day of the month is right-justified, whereas on Windows
  31 	Python 2.7 it is padded with zeros.
  32 
  33 	See https://github.com/fonttools/fonttools/issues/455
  34 	"""
  35 	if t is None:
  36 		t = time.localtime()
  37 	s = "%s %s %2s %s" % (
  38 		DAYNAMES[t.tm_wday], MONTHNAMES[t.tm_mon], t.tm_mday,
  39 		time.strftime("%H:%M:%S %Y", t))
  40 	return s
  41 
  42 
  43 def timestampToString(value):
  44 	return asctime(time.gmtime(max(0, value + epoch_diff)))
  45 
  46 def timestampFromString(value):
  47 	return calendar.timegm(time.strptime(value)) - epoch_diff
  48 
  49 def timestampNow():
  50 	# https://reproducible-builds.org/specs/source-date-epoch/
  51 	source_date_epoch = os.environ.get("SOURCE_DATE_EPOCH")
  52 	if source_date_epoch is not None:
  53 		return int(source_date_epoch) - epoch_diff
  54 	return int(time.time() - epoch_diff)
  55 
  56 def timestampSinceEpoch(value):
  57 	return int(value - epoch_diff)
  58 
  59 
  60 if __name__ == "__main__":
  61 	import sys
  62 	import doctest
  63 	sys.exit(doctest.testmod().failed)
  64
  ```
  --- END FILES ---
  
  Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.
  
  Here is an example:
  
  ```diff
  diff --git a/examples/server_async.py b/examples/server_async.py
  --- a/examples/server_async.py
  +++ b/examples/server_async.py
  @@ -313,4 +313,4 @@
   
   
   if __name__ == "__main__":
  -    asyncio.run(run_async_server("."), debug=True)
  +    asyncio.run(run_async_server(), debug=True)
  diff --git a/examples/server_sync.py b/examples/server_sync.py
  --- a/examples/server_sync.py
  +++ b/examples/server_sync.py
  @@ -313,5 +313,5 @@
   
   
   if __name__ == "__main__":
  -    server = run_sync_server(".")
  +    server = run_sync_server()
       server.shutdown()
  
  ```
  
golden_diff: diff --git a/Lib/fontTools/misc/timeTools.py b/Lib/fontTools/misc/timeTools.py
  --- a/Lib/fontTools/misc/timeTools.py
  +++ b/Lib/fontTools/misc/timeTools.py
  @@ -4,6 +4,7 @@
   from fontTools.misc.py23 import *
   import os
   import time
  +from datetime import datetime, timezone
   import calendar
   
   
  @@ -44,7 +45,12 @@
   	return asctime(time.gmtime(max(0, value + epoch_diff)))
   
   def timestampFromString(value):
  -	return calendar.timegm(time.strptime(value)) - epoch_diff
  +	wkday, mnth = value[:7].split()
  +	t = datetime.strptime(value[7:], ' %d %H:%M:%S %Y')
  +	t = t.replace(month=MONTHNAMES.index(mnth), tzinfo=timezone.utc)
  +	wkday_idx = DAYNAMES.index(wkday)
  +	assert t.weekday() == wkday_idx, '"' + value + '" has inconsistent weekday'
  +	return int(t.timestamp()) - epoch_diff
   
   def timestampNow():
   	# https://reproducible-builds.org/specs/source-date-epoch/
  
verification_info: {"golden_diff": "diff --git a/Lib/fontTools/misc/timeTools.py b/Lib/fontTools/misc/timeTools.py\n--- a/Lib/fontTools/misc/timeTools.py\n+++ b/Lib/fontTools/misc/timeTools.py\n@@ -4,6 +4,7 @@\n from fontTools.misc.py23 import *\n import os\n import time\n+from datetime import datetime, timezone\n import calendar\n \n \n@@ -44,7 +45,12 @@\n \treturn asctime(time.gmtime(max(0, value + epoch_diff)))\n \n def timestampFromString(value):\n-\treturn calendar.timegm(time.strptime(value)) - epoch_diff\n+\twkday, mnth = value[:7].split()\n+\tt = datetime.strptime(value[7:], ' %d %H:%M:%S %Y')\n+\tt = t.replace(month=MONTHNAMES.index(mnth), tzinfo=timezone.utc)\n+\twkday_idx = DAYNAMES.index(wkday)\n+\tassert t.weekday() == wkday_idx, '\"' + value + '\" has inconsistent weekday'\n+\treturn int(t.timestamp()) - epoch_diff\n \n def timestampNow():\n \t# https://reproducible-builds.org/specs/source-date-epoch/\n", "issue": "Importing a TTFont from XML fails when LC_TIME is set\nImporting a font from XML while LC_TIME locale is set to non-English, causes an error.\r\n\r\n### How to reproduce?\r\n\r\nThis might be easy when a non-English locale is available in the system. I came across this, while using a package on top. The corresponding issue in their package is amueller/word_cloud#530. There is a script to reproduce, which only throws an error, when a non-English locale like 'de_DE' is set with e. g. `locale.setlocale(locale.LC_TIME, 'de_DE.UTF-8')` or just by opening Spyder-IDE.\r\n\r\n**A simplified test is:**\r\n```python\r\nimport locale\r\nlocale.setlocale(locale.LC_TIME, 'de_DE.UTF-8') # works if de_DE is available\r\n\r\nfrom fontTools.misc.timeTools import timestampFromString,timestampToString,timestampNow\r\nts_now = timestampNow()\r\nstr_now = timestampToString(ts_now)\r\ntimestampFromString(str_now) # ValueError\r\n```\r\n\r\nLet's go into the cause of the error.\r\n\r\n### Basics\r\n\r\nThe locale for LC_TIME can be checked with\r\n```python\r\nimport locale\r\nprint(locale.getlocale(locale.LC_TIME))\r\n```\r\nThis outputs `('de_DE', 'UTF-8')` in my case.\r\n\r\nWith this locale the following fails:\r\n```python\r\nimport time\r\ntime.strptime('Mon', '%a')\r\n# ValueError: unconverted data remains: n\r\n```\r\n`'Mo'` is the localized abbreviation in de_DE for Monday.\r\n\r\n### TTFont\r\n\r\nThe method [`importXML`](https://github.com/fonttools/fonttools/blob/master/Lib/fontTools/ttLib/ttFont.py#L318) in `TTFont` receives the font object as XML. This can contain created and modified dates. The XML is parsed by the `XMLReader`, which somehow uses the [`fromXML`](https://github.com/fonttools/fonttools/blob/master/Lib/fontTools/ttLib/tables/_h_e_a_d.py#L107) method in `table__h_e_a_d`. There the created and modified dates are parsed using [`timestampFromString`](https://github.com/fonttools/fonttools/blob/master/Lib/fontTools/misc/timeTools.py#L46) from timeTools. This helper function uses `time.strptime(value)`.\r\n\r\nIn my test case `value` is initialized from the 'created' attribute of a font as `'Mon Jan 8 12:28:04 2007'`, which throws the following error:\r\n```\r\nValueError: time data 'Mon Jan  8 12:28:04 2007' does not match format '%a %b %d %H:%M:%S %Y'\r\n```\r\n\r\n\r\n### How to resolve?\r\n\r\nI think the parsing should be done without locale, since the XML attribute is likely to be non-local. In the opposite function [`timestampToString`](https://github.com/fonttools/fonttools/blob/master/Lib/fontTools/misc/timeTools.py#L43) `asctime` is used, which uses a fixed list of abbreviated week days and months. So that is not localized. Hence [`timestampFromString`](https://github.com/fonttools/fonttools/blob/master/Lib/fontTools/misc/timeTools.py#L46) shouldn't be localized as well.\r\n\r\nA simple solution could be\r\n```python\r\ndef timestampFromString(value):\r\n\timport locale\r\n\tl = locale.getlocale(locale.LC_TIME)\r\n\tlocale.setlocale(locale.LC_TIME, 'C')\r\n\ttry:\r\n\t\tt = time.strptime(value)\r\n\tfinally:\r\n\t\tlocale.setlocale(locale.LC_TIME, l)\r\n\treturn calendar.timegm(t) - epoch_diff\r\n```\r\n\r\nHowever, changing the locale is not recommended. It's better to use a function that can parse a date with specified locale without changing it. You could use [dateparser](https://dateparser.readthedocs.io/en/latest/) for example, but I don't know about your dependencies and how you handle it.\n", "before_files": [{"content": "\"\"\"fontTools.misc.timeTools.py -- tools for working with OpenType timestamps.\n\"\"\"\n\nfrom fontTools.misc.py23 import *\nimport os\nimport time\nimport calendar\n\n\nepoch_diff = calendar.timegm((1904, 1, 1, 0, 0, 0, 0, 0, 0))\n\nDAYNAMES = [\"Mon\", \"Tue\", \"Wed\", \"Thu\", \"Fri\", \"Sat\", \"Sun\"]\nMONTHNAMES = [None, \"Jan\", \"Feb\", \"Mar\", \"Apr\", \"May\", \"Jun\",\n\t\t\t  \"Jul\", \"Aug\", \"Sep\", \"Oct\", \"Nov\", \"Dec\"]\n\n\ndef asctime(t=None):\n\t\"\"\"\n\tConvert a tuple or struct_time representing a time as returned by gmtime()\n\tor localtime() to a 24-character string of the following form:\n\n\t>>> asctime(time.gmtime(0))\n\t'Thu Jan  1 00:00:00 1970'\n\n\tIf t is not provided, the current time as returned by localtime() is used.\n\tLocale information is not used by asctime().\n\n\tThis is meant to normalise the output of the built-in time.asctime() across\n\tdifferent platforms and Python versions.\n\tIn Python 3.x, the day of the month is right-justified, whereas on Windows\n\tPython 2.7 it is padded with zeros.\n\n\tSee https://github.com/fonttools/fonttools/issues/455\n\t\"\"\"\n\tif t is None:\n\t\tt = time.localtime()\n\ts = \"%s %s %2s %s\" % (\n\t\tDAYNAMES[t.tm_wday], MONTHNAMES[t.tm_mon], t.tm_mday,\n\t\ttime.strftime(\"%H:%M:%S %Y\", t))\n\treturn s\n\n\ndef timestampToString(value):\n\treturn asctime(time.gmtime(max(0, value + epoch_diff)))\n\ndef timestampFromString(value):\n\treturn calendar.timegm(time.strptime(value)) - epoch_diff\n\ndef timestampNow():\n\t# https://reproducible-builds.org/specs/source-date-epoch/\n\tsource_date_epoch = os.environ.get(\"SOURCE_DATE_EPOCH\")\n\tif source_date_epoch is not None:\n\t\treturn int(source_date_epoch) - epoch_diff\n\treturn int(time.time() - epoch_diff)\n\ndef timestampSinceEpoch(value):\n\treturn int(value - epoch_diff)\n\n\nif __name__ == \"__main__\":\n\timport sys\n\timport doctest\n\tsys.exit(doctest.testmod().failed)\n", "path": "Lib/fontTools/misc/timeTools.py"}], "after_files": [{"content": "\"\"\"fontTools.misc.timeTools.py -- tools for working with OpenType timestamps.\n\"\"\"\n\nfrom fontTools.misc.py23 import *\nimport os\nimport time\nfrom datetime import datetime, timezone\nimport calendar\n\n\nepoch_diff = calendar.timegm((1904, 1, 1, 0, 0, 0, 0, 0, 0))\n\nDAYNAMES = [\"Mon\", \"Tue\", \"Wed\", \"Thu\", \"Fri\", \"Sat\", \"Sun\"]\nMONTHNAMES = [None, \"Jan\", \"Feb\", \"Mar\", \"Apr\", \"May\", \"Jun\",\n\t\t\t  \"Jul\", \"Aug\", \"Sep\", \"Oct\", \"Nov\", \"Dec\"]\n\n\ndef asctime(t=None):\n\t\"\"\"\n\tConvert a tuple or struct_time representing a time as returned by gmtime()\n\tor localtime() to a 24-character string of the following form:\n\n\t>>> asctime(time.gmtime(0))\n\t'Thu Jan  1 00:00:00 1970'\n\n\tIf t is not provided, the current time as returned by localtime() is used.\n\tLocale information is not used by asctime().\n\n\tThis is meant to normalise the output of the built-in time.asctime() across\n\tdifferent platforms and Python versions.\n\tIn Python 3.x, the day of the month is right-justified, whereas on Windows\n\tPython 2.7 it is padded with zeros.\n\n\tSee https://github.com/fonttools/fonttools/issues/455\n\t\"\"\"\n\tif t is None:\n\t\tt = time.localtime()\n\ts = \"%s %s %2s %s\" % (\n\t\tDAYNAMES[t.tm_wday], MONTHNAMES[t.tm_mon], t.tm_mday,\n\t\ttime.strftime(\"%H:%M:%S %Y\", t))\n\treturn s\n\n\ndef timestampToString(value):\n\treturn asctime(time.gmtime(max(0, value + epoch_diff)))\n\ndef timestampFromString(value):\n\twkday, mnth = value[:7].split()\n\tt = datetime.strptime(value[7:], ' %d %H:%M:%S %Y')\n\tt = t.replace(month=MONTHNAMES.index(mnth), tzinfo=timezone.utc)\n\twkday_idx = DAYNAMES.index(wkday)\n\tassert t.weekday() == wkday_idx, '\"' + value + '\" has inconsistent weekday'\n\treturn int(t.timestamp()) - epoch_diff\n\ndef timestampNow():\n\t# https://reproducible-builds.org/specs/source-date-epoch/\n\tsource_date_epoch = os.environ.get(\"SOURCE_DATE_EPOCH\")\n\tif source_date_epoch is not None:\n\t\treturn int(source_date_epoch) - epoch_diff\n\treturn int(time.time() - epoch_diff)\n\ndef timestampSinceEpoch(value):\n\treturn int(value - epoch_diff)\n\n\nif __name__ == \"__main__\":\n\timport sys\n\timport doctest\n\tsys.exit(doctest.testmod().failed)\n", "path": "Lib/fontTools/misc/timeTools.py"}]}