首页 > 解决方案 > “获取一个地方的开放和关闭时间,如果 DateTime.Now 介于标记为开放之间”在本地工作,但在发布后不在服务器上

问题描述

我在本地调试与在服务器上发布时遇到问题。

我需要知道一家商店是否在 2 次之间营业,例如:

if ((timeNow >= openHour) && (timeNow <= closeHour))

如果是,请告诉用户商店是关闭还是营业。

编辑

我的问题基本上是: 每分钟更新商店状态的 Cron 作业会查询商店的时区,并且每个商店都会将其 DateTime.UtcNow 调整到该时区,它在本地调试时有效,但在我发布代码和查询时无效商店的状态。

这是我正在尝试做的事情:

StoreHours.cs

public class StoreHour : AuditableEntities
{
    public StoreHour()
    {

    }

    public Guid StoreHourId { get; set; }
    public Guid DayOfTheWeekId { get; set; }
    public virtual DayOfTheWeek DayOfTheWeek { get; set; }
    public DateTime OpenHour { get; set; }
    public DateTime CloseHour { get; set; }
    public Guid PlaceId { get; set; }
    public virtual Place Place { get; set; }
}

AppDbContext.cs(种子数据)

// Hours for the first store
var cscOpeningHour = DateTime.ParseExact("11:30:00 AM", "hh:mm:ss tt", CultureInfo.InvariantCulture);
cscOpeningHour = DateTime.SpecifyKind(cscOpeningHour, DateTimeKind.Utc);
var cscClosingHour = DateTime.ParseExact("10:00:00 PM", "hh:mm:ss tt", CultureInfo.InvariantCulture);
cscClosingHour = DateTime.SpecifyKind(cscClosingHour, DateTimeKind.Utc);

// Hours for the second store ( have multiple because closing time is the next day ( 02:00:00 AM )
var jOpeningHour1 = DateTime.ParseExact("12:00:00 AM", "hh:mm:ss tt", CultureInfo.InvariantCulture);
jOpeningHour1 = DateTime.SpecifyKind(jOpeningHour1, DateTimeKind.Utc);
var jClosingHour1 = DateTime.ParseExact("02:00:00 AM", "hh:mm:ss tt", CultureInfo.InvariantCulture);
jClosingHour1 = DateTime.SpecifyKind(jClosingHour1, DateTimeKind.Utc);
var jOpeningHour2 = DateTime.ParseExact("05:00:00 PM", "hh:mm:ss tt", CultureInfo.InvariantCulture);
jOpeningHour2 = DateTime.SpecifyKind(jOpeningHour2, DateTimeKind.Utc);
var jClosingHour2 = DateTime.ParseExact("11:59:59 PM", "hh:mm:ss tt", CultureInfo.InvariantCulture);
jClosingHour2 = DateTime.SpecifyKind(jClosingHour2, DateTimeKind.Utc);

// Seed data
modelBuilder.Entity<StoreHour>().HasData(new StoreHour
        {
            StoreHourId = Guid.NewGuid(),
            DayOfTheWeekId = mondayDayOfTheWeekId,
            OpenHour = cscOpeningHour,
            CloseHour = cscClosingHour,
            PlaceId = cscPlaceId
        });

更新DeviceCommandHandler.cs

public async Task<Unit> Handle(UpdateDeviceCommand request, CancellationToken cancellationToken)
    {
        var devices = await repository.GetAllDevicesWithRelatedData();
        foreach (var device in devices)
        {
            var count = await repository.GetNumber(device.DeviceId);

            var thePlace = await placeRepository.GetPlaceByIdWithRelatedData(device.Place.PlaceId);

            var timeNow = TimeZoneInfo.ConvertTime(
                              DateTime.Now,
                              TimeZoneInfo.FindSystemTimeZoneById(thePlace.Timezone.Name));

            var day = DateTime.UtcNow.DayOfWeek.ToString();

            if (thePlace.StoreHours.Count() > 7)
            {
                // OpenHour and CloseHour are DateTime properties
                // returns "12:00:00 AM"
                var openHour1 = thePlace.StoreHours.OrderBy(d => d.OpenHour).Select(d => d.OpenHour).First().ToString("hh:mm:ss tt");
                // returns "2:00:00 AM"
                var closeHour1 = thePlace.StoreHours.OrderBy(d => d.CloseHour).Select(d => d.CloseHour).First().ToString("hh:mm:ss tt");
                // returns "05:00:00 PM"
                var openHour2 = thePlace.StoreHours.OrderByDescending(d => d.OpenHour).Select(d => d.OpenHour).First().ToString("hh:mm:ss tt");
                // returns "11:59:59 PM"
                var closeHour2 = thePlace.StoreHours.OrderByDescending(d => d.CloseHour).Select(d => d.CloseHour).First().ToString("hh:mm:ss tt");

                // returns today's date and time: mm/dd/yyyy - 12:00:00 AM
                // Which is the right time converted to the place's timezone
                var theOpenHour1 = DateTime.Parse(openHour1);
                theOpenHour1 = TimeZoneInfo.ConvertTime(
                              theOpenHour1,
                              TimeZoneInfo.FindSystemTimeZoneById(thePlace.Timezone.Name));
                var theCloseHour1 = DateTime.Parse(closeHour1);
                theCloseHour1 = TimeZoneInfo.ConvertTime(
                              theCloseHour1,
                              TimeZoneInfo.FindSystemTimeZoneById(thePlace.Timezone.Name));
                var theOpenHour2 = DateTime.Parse(openHour2);
                theOpenHour2 = TimeZoneInfo.ConvertTime(
                              theOpenHour2,
                              TimeZoneInfo.FindSystemTimeZoneById(thePlace.Timezone.Name));
                var theCloseHour2 = DateTime.Parse(closeHour2);
                theCloseHour2 = TimeZoneInfo.ConvertTime(
                              theCloseHour2,
                              TimeZoneInfo.FindSystemTimeZoneById(thePlace.Timezone.Name));

                if ((timeNow >= theOpenHour1) && (timeNow <= theCloseHour1)
                     || (timeNow >= theOpenHour2) && (timeNow <= theCloseHour2))
                {
                    if (count != 0)
                    {
                        device.Ratio = (double)device.Count / (double)count;
                    }
                    else
                    {
                        count += 1;
                        device.Ratio = (double)device.Count / (double)count;
                    }

                    if (device.Ratio == 2)
                    {
                        //
                    }
                    if (...)
                    {
                        //
                    }

                    repository.Update(device);
                }
                else
                {
                    //

                    repository.Update(device);
                }
            }

            else
            {
                var openHour = thePlace.StoreHours.Select(d => d.OpenHour).First().ToString("hh:mm:ss tt");
                var closeHour = thePlace.StoreHours.Select(d => d.CloseHour).First().ToString("hh:mm:ss tt");

                DateTime dtOpen = DateTime.Parse(openHour);
                dtOpen = TimeZoneInfo.ConvertTime(
                              dtOpen,
                              TimeZoneInfo.FindSystemTimeZoneById(thePlace.Timezone.Name));
                DateTime dtClose = DateTime.Parse(closeHour);
                dtClose = TimeZoneInfo.ConvertTime(
                              dtClose,
                              TimeZoneInfo.FindSystemTimeZoneById(thePlace.Timezone.Name));

                if ((timeNow >= dtOpen) && (timeNow <= dtClose))
                {
                    if (count != 0)
                    {
                        device.Ratio = (double)device.Count/ (double)count;
                    }
                    else
                    {
                        count += 1;
                        device.Ratio = (double)device.Count/ (double)count;
                    }

                    if (device.Ratio == 2)
                    {
                        //
                    }
                    if (...)
                    {
                        //
                    }

                    repository.Update(device);
                }
                else
                {
                    //

                    repository.Update(device);
                }
            }

        await repository.SaveChanges();

        return Unit.Value;

        }

正如@JonasH 所说,我应该使用 TimeSpan 但在此之前,我真的很想了解它为什么在本地而不是远程工作。我正在将无效日期的时间“12:00:00 AM”转换为有效的 DateTime,并转换为该地点的 TimeZone(就在 if 语句之前)。当我调试它时它可以工作,因为比较的时间是同一天和正确的时间,让我困惑的是为什么不在服务器上,是什么我没有转换或不做这使得服务器不做。

我确定它与时间转换有关,因为我的计算机获取本地时间,但我不知道服务器在转换代码中的时间值后如何出错。

非常感谢你的帮助 !

标签: c#datetime

解决方案


我需要知道一家商店是否在 2 次之间营业。

我建议将开/关时间存储为代表一天中的时间(即从一天开始的时间)和商店的时区的 TimeSpan。

.Net 6 正在引入一种TimeOnly类型,它提供了比时间跨度更好的“一天中的时间”表示。还有更完整的日期/时间相关类型集的NodaTime

然后,您可以使用 TimeZoneInfo 获取特定时区的当前时间:

var timeOfDayForStore = TimeZoneInfo.ConvertTime(
                                  DateTime.Now,
                                  TimeZoneInfo.FindSystemTimeZoneById(myStoreTimeZone))
                                 .TimeOfDay;
if(myStoreOpenTime < timeOfDayForStore && myStoreCloseTime > timeOfDayForStore){
    ...
}

请注意,这是假设商店在午夜不营业。


推荐阅读