ASP.NET WebAPI slow responses at the initial phase - iis
I made an empty project referencing only a Web API and tweaked these simple APIs to see if there're any performance differences and any possible hangs on one of the async jobs.
public class TestController : ApiController
{
[HttpGet]
[Route("Welcome")]
public async Task<string> Welcome()
{
string r = await SlowMethod();
return r;
}
public async Task<string> SlowMethod()
{
Thread.Sleep(3000);
return await Task.FromResult("data");
}
[HttpGet]
[Route("WelcomeSync")]
public string WelcomeSync()
{
string r = SlowSyncMethod();
return r;
}
public string SlowSyncMethod()
{
Thread.Sleep(3000);
return "data";
}
}
And I ran the API tests using jMeter with this test plan. The result is pretty much the same in terms of throughput, but there's a noticeable difference in "Max" item in this result table from jMeter.
Label Samples Average Min Max Std.Dev Error% Throughput Received KB/sec Sent KB/sec Avg.Bytes
Async 100000 3193 3000 [32046] 1343.6219321793749 0.0 62.534550339062335 21.557320575868168 7.69468099875181 353.0
Sync 100000 3003 3000 [3050] 3.523236520886259 0.0 66.54055014396047 23.458143165986066 8.447530779994983 361.0
Max is the millisecond unit by the way. Each APIs is supposed to take at least 3 seconds per a request as the result of Thread.Sleep(3000); But one of the requests, or some of them, took 32 seconds to be done.
Does this mean there was a hang on at least one async job? If there was, what's the culprit for the hang?
UPDATED
I once suspected hanging behaviour on the async job, but it turned out that's not the case. Just changing the test order puts out the same result. The first test will be always slow at the beginning of the test. This was completely not related to async vs sync job whatsoever.
Anyway I tried to leave logs between the SlowMethod(); using Stopwatch to see if there is actual hanging on the async method and soon I found out there's no hanging for sure on both async and sync APIs. The logs always print "It took 3 seconds".
2018-08-12 13:40:11 "Welcome async 'Welcome'. It took 3 seconds"
2018-08-12 13:40:14 "Welcome async 'Welcome'. It took 3 seconds"
2018-08-12 13:40:17 "Welcome async 'Welcome'. It took 3 seconds"
.
.
.
What was late was the HTTP response itself. And there was a certain, noticeable characteristic on the slowness.
The performance starts to lose its pace shortly.
It keeps slowing down until it reaches 30~40 seconds processing
After that it starts to recover from the dragging performances.
Eventually it keeps responding within 3 seconds till the end.
This is the logs that will help you picture better.
2018-08-04 04:48:50.030 +09:00 [INF] CurrentThread 12, Context LeaseLifeTimeServiceProperty, Time passed 3. The result was "data"
2018-08-04 04:48:50.030 +09:00 [INF] CurrentThread 11, Context LeaseLifeTimeServiceProperty, Time passed 3. The result was "data"
2018-08-04 04:48:50.030 +09:00 [INF] CurrentThread 9, Context LeaseLifeTimeServiceProperty, Time passed 3. The result was "data"
2018-08-04 04:48:50.030 +09:00 [INF] CurrentThread 10, Context LeaseLifeTimeServiceProperty, Time passed 3. The result was "data"
2018-08-04 04:48:50.632 +09:00 [INF] CurrentThread 11, Context LeaseLifeTimeServiceProperty, Time passed 4. The result was "data"
2018-08-04 04:48:51.637 +09:00 [INF] CurrentThread 14, Context LeaseLifeTimeServiceProperty, Time passed 5. The result was "data"
2018-08-04 04:48:52.631 +09:00 [INF] CurrentThread 14, Context LeaseLifeTimeServiceProperty, Time passed 6. The result was "data"
2018-08-04 04:48:52.968 +09:00 [INF] CurrentThread 14, Context LeaseLifeTimeServiceProperty, Time passed 6. The result was "data"
2018-08-04 04:48:52.969 +09:00 [INF] CurrentThread 12, Context LeaseLifeTimeServiceProperty, Time passed 6. The result was "data"
2018-08-04 04:48:52.969 +09:00 [INF] CurrentThread 14, Context LeaseLifeTimeServiceProperty, Time passed 6. The result was "data"
2018-08-04 04:48:52.973 +09:00 [INF] CurrentThread 14, Context LeaseLifeTimeServiceProperty, Time passed 6. The result was "data"
2018-08-04 04:48:53.631 +09:00 [INF] CurrentThread 14, Context LeaseLifeTimeServiceProperty, Time passed 7. The result was "data"
2018-08-04 04:48:53.637 +09:00 [INF] CurrentThread 14, Context LeaseLifeTimeServiceProperty, Time passed 7. The result was "data"
2018-08-04 04:48:54.631 +09:00 [INF] CurrentThread 14, Context LeaseLifeTimeServiceProperty, Time passed 8. The result was "data"
2018-08-04 04:48:54.640 +09:00 [INF] CurrentThread 14, Context LeaseLifeTimeServiceProperty, Time passed 8. The result was "data"
2018-08-04 04:48:55.633 +09:00 [INF] CurrentThread 14, Context LeaseLifeTimeServiceProperty, Time passed 9. The result was "data"
2018-08-04 04:48:55.635 +09:00 [INF] CurrentThread 14, Context LeaseLifeTimeServiceProperty, Time passed 9. The result was "data"
2018-08-04 04:48:55.975 +09:00 [INF] CurrentThread 14, Context LeaseLifeTimeServiceProperty, Time passed 9. The result was "data"
2018-08-04 04:48:55.976 +09:00 [INF] CurrentThread 12, Context LeaseLifeTimeServiceProperty, Time passed 9. The result was "data"
2018-08-04 04:48:55.976 +09:00 [INF] CurrentThread 11, Context LeaseLifeTimeServiceProperty, Time passed 9. The result was "data"
2018-08-04 04:48:55.979 +09:00 [INF] CurrentThread 11, Context LeaseLifeTimeServiceProperty, Time passed 9. The result was "data"
2018-08-04 04:48:56.633 +09:00 [INF] CurrentThread 11, Context LeaseLifeTimeServiceProperty, Time passed 10. The result was "data"
2018-08-04 04:48:56.636 +09:00 [INF] CurrentThread 11, Context LeaseLifeTimeServiceProperty, Time passed 10. The result was "data"
2018-08-04 04:48:56.642 +09:00 [INF] CurrentThread 11, Context LeaseLifeTimeServiceProperty, Time passed 10. The result was "data"
.
.
.
2018-08-04 04:49:04.647 +09:00 [INF] CurrentThread 14, Context LeaseLifeTimeServiceProperty, Time passed 18. The result was "data"
2018-08-04 04:49:04.650 +09:00 [INF] CurrentThread 14, Context LeaseLifeTimeServiceProperty, Time passed 18. The result was "data"
2018-08-04 04:49:04.994 +09:00 [INF] CurrentThread 12, Context LeaseLifeTimeServiceProperty, Time passed 18. The result was "data"
2018-08-04 04:49:04.994 +09:00 [INF] CurrentThread 14, Context LeaseLifeTimeServiceProperty, Time passed 18. The result was "data"
2018-08-04 04:49:04.998 +09:00 [INF] CurrentThread 14, Context LeaseLifeTimeServiceProperty, Time passed 18. The result was "data"
2018-08-04 04:49:04.999 +09:00 [INF] CurrentThread 12, Context LeaseLifeTimeServiceProperty, Time passed 18. The result was "data"
2018-08-04 04:49:05.633 +09:00 [INF] CurrentThread 12, Context LeaseLifeTimeServiceProperty, Time passed 19. The result was "data"
2018-08-04 04:49:05.636 +09:00 [INF] CurrentThread 12, Context LeaseLifeTimeServiceProperty, Time passed 19. The result was "data"
2018-08-04 04:49:05.640 +09:00 [INF] CurrentThread 12, Context LeaseLifeTimeServiceProperty, Time passed 19. The result was "data"
2018-08-04 04:49:05.643 +09:00 [INF] CurrentThread 11, Context LeaseLifeTimeServiceProperty, Time passed 19. The result was "data"
2018-08-04 04:49:05.646 +09:00 [INF] CurrentThread 11, Context LeaseLifeTimeServiceProperty, Time passed 19. The result was "data"
2018-08-04 04:49:05.652 +09:00 [INF] CurrentThread 11, Context LeaseLifeTimeServiceProperty, Time passed 19. The result was "data"
2018-08-04 04:49:06.633 +09:00 [INF] CurrentThread 11, Context LeaseLifeTimeServiceProperty, Time passed 20. The result was "data"
2018-08-04 04:49:06.638 +09:00 [INF] CurrentThread 11, Context LeaseLifeTimeServiceProperty, Time passed 20. The result was "data"
2018-08-04 04:49:06.641 +09:00 [INF] CurrentThread 11, Context LeaseLifeTimeServiceProperty, Time passed 20. The result was "data"
2018-08-04 04:49:06.643 +09:00 [INF] CurrentThread 11, Context LeaseLifeTimeServiceProperty, Time passed 20. The result was "data"
2018-08-04 04:49:06.647 +09:00 [INF] CurrentThread 12, Context LeaseLifeTimeServiceProperty, Time passed 20. The result was "data"
2018-08-04 04:49:06.655 +09:00 [INF] CurrentThread 12, Context LeaseLifeTimeServiceProperty, Time passed 20. The result was "data"
.
.
.
2018-08-04 04:49:15.634 +09:00 [INF] CurrentThread 14, Context LeaseLifeTimeServiceProperty, Time passed 28. The result was "data"
2018-08-04 04:49:15.639 +09:00 [INF] CurrentThread 14, Context LeaseLifeTimeServiceProperty, Time passed 28. The result was "data"
2018-08-04 04:49:15.644 +09:00 [INF] CurrentThread 14, Context LeaseLifeTimeServiceProperty, Time passed 28. The result was "data"
2018-08-04 04:49:15.648 +09:00 [INF] CurrentThread 14, Context LeaseLifeTimeServiceProperty, Time passed 28. The result was "data"
2018-08-04 04:49:15.652 +09:00 [INF] CurrentThread 14, Context LeaseLifeTimeServiceProperty, Time passed 29. The result was "data"
2018-08-04 04:49:15.653 +09:00 [INF] CurrentThread 14, Context LeaseLifeTimeServiceProperty, Time passed 29. The result was "data"
2018-08-04 04:49:15.655 +09:00 [INF] CurrentThread 14, Context LeaseLifeTimeServiceProperty, Time passed 29. The result was "data"
2018-08-04 04:49:15.665 +09:00 [INF] CurrentThread 14, Context LeaseLifeTimeServiceProperty, Time passed 29. The result was "data"
2018-08-04 04:49:16.635 +09:00 [INF] CurrentThread 14, Context LeaseLifeTimeServiceProperty, Time passed 29. The result was "data"
2018-08-04 04:49:16.638 +09:00 [INF] CurrentThread 12, Context LeaseLifeTimeServiceProperty, Time passed 29. The result was "data"
2018-08-04 04:49:16.647 +09:00 [INF] CurrentThread 12, Context LeaseLifeTimeServiceProperty, Time passed 30. The result was "data"
2018-08-04 04:49:16.650 +09:00 [INF] CurrentThread 11, Context LeaseLifeTimeServiceProperty, Time passed 29. The result was "data"
2018-08-04 04:49:16.669 +09:00 [INF] CurrentThread 12, Context LeaseLifeTimeServiceProperty, Time passed 30. The result was "data"
2018-08-04 04:49:16.669 +09:00 [INF] CurrentThread 14, Context LeaseLifeTimeServiceProperty, Time passed 30. The result was "data"
2018-08-04 04:49:16.669 +09:00 [INF] CurrentThread 11, Context LeaseLifeTimeServiceProperty, Time passed 30. The result was "data"
2018-08-04 04:49:16.670 +09:00 [INF] CurrentThread 10, Context LeaseLifeTimeServiceProperty, Time passed 30. The result was "data"
2018-08-04 04:49:16.673 +09:00 [INF] CurrentThread 12, Context LeaseLifeTimeServiceProperty, Time passed 30. The result was "data"
2018-08-04 04:49:17.014 +09:00 [INF] CurrentThread 16, Context LeaseLifeTimeServiceProperty, Time passed 30. The result was
2018-08-04 04:49:17.662 +09:00 [INF] CurrentThread 16, Context LeaseLifeTimeServiceProperty, Time passed 30. The result was "data"
2018-08-04 04:49:17.668 +09:00 [INF] CurrentThread 12, Context LeaseLifeTimeServiceProperty, Time passed 31. The result was "data"
2018-08-04 04:49:17.675 +09:00 [INF] CurrentThread 11, Context LeaseLifeTimeServiceProperty, Time passed 31. The result was "data"
2018-08-04 04:49:17.676 +09:00 [INF] CurrentThread 14, Context LeaseLifeTimeServiceProperty, Time passed 31. The result was "data"
2018-08-04 04:49:18.634 +09:00 [INF] CurrentThread 14, Context LeaseLifeTimeServiceProperty, Time passed 31. The result was "data"
2018-08-04 04:49:18.644 +09:00 [INF] CurrentThread 10, Context LeaseLifeTimeServiceProperty, Time passed 31. The result was "data"
2018-08-04 04:49:18.647 +09:00 [INF] CurrentThread 14, Context LeaseLifeTimeServiceProperty, Time passed 31. The result was "data"
2018-08-04 04:49:18.648 +09:00 [INF] CurrentThread 15, Context LeaseLifeTimeServiceProperty, Time passed 31. The result was "data"
2018-08-04 04:49:18.651 +09:00 [INF] CurrentThread 15, Context LeaseLifeTimeServiceProperty, Time passed 31. The result was "data"
2018-08-04 04:49:18.654 +09:00 [INF] CurrentThread 15, Context LeaseLifeTimeServiceProperty, Time passed 31. The result was "data"
2018-08-04 04:49:18.661 +09:00 [INF] CurrentThread 12, Context LeaseLifeTimeServiceProperty, Time passed 31. The result was "data"
2018-08-04 04:49:18.668 +09:00 [INF] CurrentThread 11, Context LeaseLifeTimeServiceProperty, Time passed 32. The result was "data"
2018-08-04 04:49:18.671 +09:00 [INF] CurrentThread 12, Context LeaseLifeTimeServiceProperty, Time passed 32. The result was "data"
2018-08-04 04:49:18.675 +09:00 [INF] CurrentThread 11, Context LeaseLifeTimeServiceProperty, Time passed 32. The result was "data"
2018-08-04 04:49:19.640 +09:00 [INF] CurrentThread 11, Context LeaseLifeTimeServiceProperty, Time passed 32. The result was "data"
2018-08-04 04:49:19.646 +09:00 [INF] CurrentThread 11, Context LeaseLifeTimeServiceProperty, Time passed 32. The result was "data"
2018-08-04 04:49:19.646 +09:00 [INF] CurrentThread 16, Context LeaseLifeTimeServiceProperty, Time passed 32. The result was "data"
2018-08-04 04:49:19.656 +09:00 [INF] CurrentThread 16, Context LeaseLifeTimeServiceProperty, Time passed 32. The result was "data"
2018-08-04 04:49:19.659 +09:00 [INF] CurrentThread 16, Context LeaseLifeTimeServiceProperty, Time passed 32. The result was "data"
2018-08-04 04:49:19.667 +09:00 [INF] CurrentThread 16, Context LeaseLifeTimeServiceProperty, Time passed 29. The result was "data"
2018-08-04 04:49:19.669 +09:00 [INF] CurrentThread 16, Context LeaseLifeTimeServiceProperty, Time passed 29. The result was "data"
2018-08-04 04:49:19.673 +09:00 [INF] CurrentThread 16, Context LeaseLifeTimeServiceProperty, Time passed 29. The result was "data"
2018-08-04 04:49:19.677 +09:00 [INF] CurrentThread 15, Context LeaseLifeTimeServiceProperty, Time passed 29. The result was "data"
2018-08-04 04:49:19.679 +09:00 [INF] CurrentThread 12, Context LeaseLifeTimeServiceProperty, Time passed 29. The result was "data"
2018-08-04 04:49:20.016 +09:00 [INF] CurrentThread 12, Context LeaseLifeTimeServiceProperty, Time passed 28. The result was "data"
2018-08-04 04:49:20.017 +09:00 [INF] CurrentThread 12, Context LeaseLifeTimeServiceProperty, Time passed 27. The result was "data"
2018-08-04 04:49:20.023 +09:00 [INF] CurrentThread 12, Context LeaseLifeTimeServiceProperty, Time passed 27. The result was "data"
.
.
.
2018-08-04 05:03:11.422 +09:00 [INF] CurrentThread 14, Context LeaseLifeTimeServiceProperty, Time passed 3. The result was "data"
2018-08-04 05:03:14.492 +09:00 [INF] CurrentThread 14, Context LeaseLifeTimeServiceProperty, Time passed 3. The result was "data"
IIS recompilation, IIS application pool recycling, and the IIS idle timeout setting were the prime suspects but it turned out that they have nothing to do with this problem. Seriously what's the reason?
While using Thread.Sleep(3000); in the sync test is ok, you will get a better representation using Task.Delay when faking long running async calls.
public async Task<string> SlowMethod() {
await Task.Delay(3000);
return "data";
}
The culprit
I finally opened up the underhood and tried to inspect every little details of what might cause this performance problem. The problem lies in ThreadPool. Well calling it a problem seems no longer right from now on.
The nature of the ThreadPool that doesn't like to create a new thread and increase the number of threads in its pool and has a tendency to fall back to the minimum number of threads whenever it is applicable is the behind scene of this phenomenon.
Well in my environment, the ThreadPool starts with 4 threads. I was able to realize this by calling.
ThreadPool.GetMinThreads(out int threadCount, out int portThread);
Having only 4 threads in the initial stage was simply not enough for dealing with the overwhelmingly incoming HTTP requests during the jMeter test. Consequently, letting ThreadPool maintain at least 200 threads so that it can start off with 200 threads solves this problem away.
ThreadPool.SetMinThreads(200, 4);
Now every requests will be processed within 3 seconds as expected to the end of the test. But manipulating the minimum number of threads in ThreadPool in a meaningless manner is not recommended because it might affect the performance in the application.
This is the Caution from MSDN
By default, the minimum number of threads is set to the number of processors on a system. You can use the SetMinThreads method to increase the minimum number of threads. However, unnecessarily increasing these values can cause performance problems. If too many tasks start at the same time, all of them might appear to be slow. In most cases, the thread pool will perform better with its own algorithm for allocating threads. Reducing the minimum to less than the number of processors can also hurt performance.
Easy solution without using SetMinThreads
Using Task.Delay(3000); instead of Thread.Sleep(3000) clears this problem away too. Since Thread.Sleep(3000) simply blocks the current thread, it may cause ThreadPool to create more threads. Actually, you can see this actually happen in the resource monitor.
This is Task.Delay(3000); version and I took this screenshot 1 min after the test has started. Only 59 threads created and the number stays the same or below during the test.
This is Thread.Sleep(3000); version and I took this at the same time. But iisexpress has spawned 116 threads and the number keeps increasing during the test.
Related
Airflow job not Scheduling after manual Trigger
I'm using Airflow version 2.2.3(Latest version). My Airflow Dag is scheduled to run "#daily". I manually triggered the Dag yesterday(2022-02-08, 09:19:22) and I expect it to be scheduled Today at 2022-02-09, 00:00:00, but the DAG was not scheduled. From the below image The last run was on 2022-02-08, 09:19:22 and the next run is scheduled at 2022-02-09, 00:00:00. But the time has already passed and it is 2022-02-09 06:22 UTC DAG parameters: {'catchup': False, 'catchup_by_default': False, 'depends_on_past': False, 'provide_context': True, 'retries': 1, 'retry_delay': datetime.timedelta(0, 300), 'start_date': DateTime(2021, 12, 31, 15, 50, 0, tzinfo=Timezone('UTC'))} Do I need to change any parameters or config values? Please suggest
Python arrow get list of years between date range
I have this function: def function(start_date_arrow=None,end_date_arrow=None, date_concept=None): list=[getattr(date, date_concept) for date in arrow.Arrow.range(date_concept, start_date_arrow, end_date_arrow)] This function works well when iterating over date_concept='month' and date_concept='day'. On the other hand, date_concept='year' only returns a list of one item. For example: start_date_arrow= arrow.get('2021-11-05') end_date_arrow= arrow.get('2022-02-05') year_list=function(start_date_arrow=start_date_arrow,end_date_arrow=end_date_arrow, date_concept='year') year_list is [2021] month_list=function(start_date_arrow=start_date_arrow,end_date_arrow=end_date_arrow, date_concept='month') month_list is [11, 12, 1, 2] day_list=function(start_date_arrow=start_date_arrow,end_date_arrow=end_date_arrow, date_concept='day') day_list is [5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30] Second and third call are okei, but first one should return [2021,2022] instead of [2021]. Any idea of what is happening in the year call?
Found the issue. If you use: start_date_arrow= arrow.get('2021-11-05') end_date_arrow= arrow.get('2022-02-05') Year difference between both is less than 1, so it only returns the first one, so to return 2022 in the list end_date_arrow should be end_date_arrow= arrow.get('2022-11-05') So I forced with an if statement the end date to be bigger just by one year, to force the return of both years.
printing datetime with tzinfo results in two different offsets [duplicate]
I'm trying to convert timezone aware datetime object to UTC and then back to it's original timezone. I have a following snippet t = datetime( 2013, 11, 22, hour=11, minute=0, tzinfo=pytz.timezone('Europe/Warsaw') ) now in ipython: In [18]: t Out[18]: datetime.datetime( 2013, 11, 22, 11, 0, tzinfo=<DstTzInfo 'Europe/Warsaw' WMT+1:24:00 STD> ) and now let's try to do conversion to UTC and back. I would expect to have the same representation as: In [19]: t.astimezone(pytz.utc).astimezone(pytz.timezone('Europe/Warsaw')) Out[19]: datetime.datetime( 2013, 11, 22, 10, 36, tzinfo=<DstTzInfo 'Europe/Warsaw' CET+1:00:00 STD> ) Yet we see that Out[18] and Out[19] differ. What's going on?
The documentation http://pytz.sourceforge.net/ states "Unfortunately using the tzinfo argument of the standard datetime constructors 'does not work' with pytz for many timezones." The code: t = datetime( 2013, 5, 11, hour=11, minute=0, tzinfo=pytz.timezone('Europe/Warsaw') ) doesn't work according to this, instead you should use the localize method: t = pytz.timezone('Europe/Warsaw').localize( datetime(2013, 5, 11, hour=11, minute=0))
How to convert list string to timestamp
I have list of US Holidays: Holidays = ["January 01, 2019","January 21, 2019","February 14, 2019","February 18, 2019","April 19, 2019","April 21, 2019","May 12, 2019","May 27, 2019","June 16, 2019","July 04, 2019","September 02, 2019","October 14, 2019","October 31, 2019","November 11, 2019","November 28, 2019","December 25, 2019"] I am converting it to datetinme stamp: for i in Holidays: print(datetime.strptime(i, "%B %d, %Y").date()) I am trying to append it to the another table but i am not getting the expected result DATE = [datetime.strptime(i, "%B %d, %Y") for i in Holidays]
I assume that you're after a string value of the datetime object in your DATE list; based on the example for loop in the question. Here's how to solve that: date = [str(datetime.strptime(holiday, "%B %d, %Y").date()) for holiday in holidays] print(date) All I've done is change your variable names, add .date() to remove the time and convert it to a string. Hope that helps
Check this. from datetime import datetime import pandas as pd Holidays = ["January 01, 2019","January 21, 2019","February 14, 2019","February 18, 2019","April 19, 2019","April 21, 2019","May 12, 2019","May 27, 2019","June 16, 2019","July 04, 2019","September 02, 2019","October 14, 2019","October 31, 2019","November 11, 2019","November 28, 2019","December 25, 2019"] converted_holidays = [] for i in Holidays: converted_holidays.append(datetime.strptime(i, "%B %d, %Y").date()) data = {'Name': ["Person1","Person2","Person3","Person4","Person5","Person6","Person7","Person8","Person9","Person10","Person11","Person12","Person13","Person14","Person15","Person16"]} df = pd.DataFrame(data) #insert the holidays in dataframe using insert() df.insert(0, "Holidays",converted_holidays , True) print(df)
Force AWS Lambda to use UTC when listing S3 objects using boto3
When retrieving a list of objects on AWS Lambda using Python 3.6 and boto3, the objects' LastModified attribute is using 'LastModified': datetime.datetime(2018, 8, 17, 1, 51, 31, tzinfo=tzlocal()). When I run my program locally, this attribute is using 'LastModified': datetime.datetime(2018, 8, 17, 1, 51, 31, tzinfo=tzutc()), which is what I want. Why is this happening? Is there a workaround that will allow me to specify UTC as part of the request? Alternatively, is there a simple way to convert these datetimes to UTC after they're returned from S3?
Running this code: from datetime import datetime from dateutil import tz from dateutil.tz import tzlocal d_local = datetime(2018, 8, 17, 1, 51, 31, tzinfo=tzlocal()) d_utc = d_local.astimezone(tz.tzutc()) The result is that d_utc is: datetime.datetime(2018, 8, 16, 15, 51, 31, tzinfo=tzutc())