You are working with naive datetime objects. For a naive datetime object, the time is assumed to be in local time, and so your local system timezone offset is first applied. From the `datetime.timestamp() documentation:
Naive datetime instances are assumed to represent local time and this method relies on the platform C mktime() function to perform the conversion.
and further on:
Note: There is no method to obtain the POSIX timestamp directly from a naive datetime instance representing UTC time. If your application uses this convention and your system timezone is not set to UTC, you can obtain the POSIX timestamp by supplying tzinfo=timezone.utc:
timestamp = dt.replace(tzinfo=timezone.utc).timestamp()
Note that you can make your date calculation logic much easier by working with daetime.date objects and using datetime.combine(); this method also accepts a new timezone value, so you can pass in the timezone.utc timezone at this stage:
from datetime import datetime, date, time, timedelta, timezone
# create first and last day of the month
first_day = date.today().replace(day=1)
last_day = (first_day + timedelta(days=31)).replace(day=1) - timedelta(days=1)
first_day = int(datetime.combine(first_day, time.min, tzinfo=timezone.utc).timestamp())
last_day = int(datetime.combine(last_day, time.min, tzinfo=timezone.utc).timestamp())
The above calculates the last day of the month by first adding 31 days (guaranteed to reach the next month whatever the current), then dropping that new date down to the first day of the month and then subtracting one day.
Demo:
>>> from datetime import datetime, date, time, timedelta, timezone
>>> first_day = date.today().replace(day=1)
>>> last_day = (first_day + timedelta(days=31)).replace(day=1) - timedelta(days=1)
>>> first_day, last_day
(datetime.date(2019, 1, 1), datetime.date(2019, 1, 31))
>>> int(datetime.combine(first_day, time.min, tzinfo=timezone.utc).timestamp())
1546300800
>>> int(datetime.combine(last_day, time.min, tzinfo=timezone.utc).timestamp())
1548892800
Note that midnight on the 31st of January leaves another 24 hours of the month left uncovered. You may want to remove the - timedelta(days=1) subtraction off of the last_day calculation above to switch to February 1st midnight (1548979200), or use time.max to shift the timestamp to 23:23:59 (1 second before midnight) on the 31st (1548979199).