Repository: joke2k/faker

Issue:
date_time_this_month logic error
The logic blows up when the current month (now.month) is December (12) as I have found out. 

faker/providers/date_time/**init**.py
`next_month_start = datetime(now.year, now.month + 1 % 12, 1, tzinfo=tzinfo)`
should be 
`next_month_start = datetime(now.year, (now.month + 1) % 12, 1, tzinfo=tzinfo)`



Discussion:
Had the same issue just right now...

Hi @mark-love , thanks for the report.

Do you mind submit a Pull Request? Really appreciate it :)

No problem, I can work on one right now.

@mark-love `now().month` is zero-based, so it needs to be compensated by doing something like:

``` python
(now.month + 2) % 12
```

@fcurella is it? From what I can tell in the documentation and experimenting is that it is between 1 and 12. https://docs.python.org/2/library/datetime.html#datetime.datetime.month

@mark-love , no you're right.

The issue is that on Nov 30th, 'next month' means December, and `12 % 12` returns `0`, when we actually need it to be `12`

I'll have to wait for tomorrow morning to dig deeper into this

@fcurella ah yes that would be it `now.month % 12 + 1` should fix it.
Do we also want/need the year to increment or is that unnecessary?

I guess the year needs to be incremented as well, "next month" in Dec '15 is Jan '16, not Jan '15..

so better be explicit, something like:

``` python
if now.month == 12:
    next_year = now.year + 1
    next_month = 1
else:
    next_year = now.year
    next_month = now.month + 1
```

Btw, the current code is failing because of operator precedence (`%` has higher precedence than `+` so `now.month + 1 % 12` is actually `now.month + (1 % 12)`), but anyways, `(now.month + 1) % 12` is broken as well, as month is one-based.

Is there any reason not to use `relativedelta` from the `dateutil` package (https://pypi.python.org/pypi/python-dateutil)? It provides a very robust way to get "next month" and is a well-known module:

``` python
import datetime
import dateutil

t = datetime.date.today()
next_month = datetime.date(t.year, t.month, 1) + dateutil.relativedelta.relativedelta(months=+1)

# In [1]: datetime.date.today()
# Out[1]: datetime.date(2015, 12, 1)

# In [2]: next_month
# Out[2]: datetime.date(2016, 1, 1)
```


Resolving patch:
diff --git a/faker/providers/date_time/__init__.py b/faker/providers/date_time/__init__.py
--- a/faker/providers/date_time/__init__.py
+++ b/faker/providers/date_time/__init__.py
@@ -2,10 +2,12 @@
 
 from __future__ import unicode_literals
 
+from datetime import timedelta
 import re
 from time import time, mktime
 
-from datetime import timedelta
+from dateutil import relativedelta
+from dateutil.tz import tzlocal
 
 from faker.generator import random
 from faker.utils.datetime_safe import date, datetime, real_date, real_datetime
@@ -15,6 +17,8 @@
 
 
 def datetime_to_timestamp(dt):
+    if dt.tzinfo is not None:
+        dt = dt.astimezone(tzlocal())
     return mktime(dt.timetuple())
 
 
@@ -356,8 +360,10 @@ def date_time_between_dates(cls, datetime_start=None, datetime_end=None, tzinfo=
         if datetime_end is None:
             datetime_end = datetime.now(tzinfo)
 
-        timestamp = random.randint(datetime_to_timestamp(datetime_start),
-                                       datetime_to_timestamp(datetime_end))
+        timestamp = random.randint(
+            datetime_to_timestamp(datetime_start),
+            datetime_to_timestamp(datetime_end),
+        )
         return datetime.fromtimestamp(timestamp, tzinfo)
 
     @classmethod
@@ -445,8 +451,8 @@ def date_time_this_month(cls, before_now=True, after_now=False, tzinfo=None):
         """
         now = datetime.now(tzinfo)
         this_month_start = now.replace(day=1, hour=0, minute=0, second=0, microsecond=0)
-        next_month_start = datetime(now.year, now.month + 1 % 12, 1, tzinfo=tzinfo)
 
+        next_month_start = this_month_start + relativedelta.relativedelta(months=1)
         if before_now and after_now:
             return cls.date_time_between_dates(this_month_start, next_month_start, tzinfo)
         elif not before_now and after_now:
diff --git a/setup.py b/setup.py
--- a/setup.py
+++ b/setup.py
@@ -53,6 +53,9 @@
     platforms=["any"],
     test_suite='faker.tests',
     zip_safe=zip_safe,
+    install_requires=[
+        "python-dateutil>=2.4",
+    ],
     extras_require={
         ':python_version=="2.6"': ['importlib'],
         ':python_version=="3.0"': ['importlib'],


Test patch:
diff --git a/faker/tests/__init__.py b/faker/tests/__init__.py
--- a/faker/tests/__init__.py
+++ b/faker/tests/__init__.py
@@ -10,6 +10,7 @@
 import time
 import unittest
 import sys
+from dateutil.tz import tzlocal
 
 try:
     from mock import patch
@@ -303,6 +304,14 @@ def test_random_element(self):
         pick = provider.random_element(choices)
         self.assertTrue(pick in choices)
 
+    def test_timezone_conversion(self):
+        from faker.providers.date_time import datetime_to_timestamp
+
+        now = datetime.datetime.now(utc).replace(microsecond=0)
+        timestamp = datetime_to_timestamp(now)
+        now_back = datetime.datetime.fromtimestamp(timestamp, utc)
+        self.assertEqual(now, now_back)
+
     def test_datetime_safe(self):
         from faker.utils import datetime_safe
         # test using example provided in module