openhour business logic

현재 식당 주문관리앱을 하나만들고있는데 openhour관련 내용을 만들어야해서 정리를 한번 해봣다.

문제

  1. openhour를 1주일 단위로 보여줘라.
  2. opehhour는 입력시 am pm 과 시간을 이용해라.
  3. timezone을 고려해라.
  4. day light saving을 고려해라.
  5. 현재 시간을 기준으로 오픈인지 아닌지를 보여줘라.

위 문제를 모두 고려해서 처리를 해야했다.

해결 방법

문제는 3가지로 압축될수 있었다.

  1. 오픈시간 입력
  2. 식당 오픈 시간을 보여주기
  3. 현재 시간을 기준으로 오픈인지 확인하기

식당 오픈 입력

입력할때 am/pm을 사용하여 입력하는 조건이여서 현지 시간을 기준으로 오픈시간을 입력한다. 그리고 dayofweek를 이용하여 0 - 6 까지 일,월…토 이렇게 정리한다. 그리고 타임존이 필요하다.

{
  "WorkStart": "01:00 PM",
  "WorkEnd": "04:00 PM",
  "isWorking": true,
  "restaurantId": "08d897fd-02e3-4386-8a1f-33ec3a9bb61e",
  "isAvailableMon": true,
  "isAvailableTue": false,
  "isAvailableWed": false,
  "isAvailableThu": false,
  "isAvailableFri": false,
  "isAvailableSat": false,
  "isAvailableSun": false,
  "timezone": "America/Los_Angeles"
}

이와 같이 서버로 보내면 서버에서는 요일별로 workstart와 workend timezone을 보내서 서버에 저장한다.

백앤드에서는 2020-01-01 이후에 이 시간을 붙여서 저장해준다.

if (request.IsAvailableMon)
{
  var openHourEntity = _mapper.Map<OpenHour>(request);
  openHourEntity.DayOfWeek = DayOfWeek.Monday;
  openHourEntity.TimeOfStartWork = getOpenHourStartDateTime(request.WorkStart);
  openHourEntity.TimeOfEndWork = getOpenHourEndDateTime(request.WorkStart,request.WorkEnd);
  _context.OpenHours.Add(openHourEntity);
}

...

private DateTime getOpenHourStartDateTime(string time)
{
    var result =  DateTime.ParseExact(
                                "01/01/2020 " + time,
                                "MM/dd/yyyy h:mm tt",
                                CultureInfo.InvariantCulture
                              );
    // Console.WriteLine(result);
    return result;
}
private DateTime getOpenHourEndDateTime(string stime,string etime)
{
  var sDateTime = DateTime.ParseExact(
                              "01/01/2020 " + stime,
                              "MM/dd/yyyy h:mm tt",
                              CultureInfo.InvariantCulture
                            );

  var eDateTime =  DateTime.ParseExact(
                              "01/01/2020 " + etime,
                              "MM/dd/yyyy h:mm tt",
                              CultureInfo.InvariantCulture
                            );

  if(sDateTime > eDateTime)
    return eDateTime.AddDays(1);
  else
    return eDateTime;
}

혹시 시작이 11pm이고 끝이 다음날 2am이면 1/2일로 넣어준다. 여기서 중요하게 생각한것은 스트링을 특정일에 datetime으로 변경을 해서 디비에 입력을 해준것이다. 그리고 이건 식당들에 로컬타임이다.

오픈시간 보여주기

오픈시간을 프론트로 가서 보여줄때 전체 날짜가 아닌 hh:mm만 보여주면 된다.

현재 시간을 기준으로 검색하기

서버 시간은 gmt 기준으로 되있다. 그리고 식당에 위치는 LA / NY 이 될수도 있다. 이들사이에는 시차가 3시간이 난다. day light saving을 적용해야한다. 이걸 처리하기 위해 다음처럼 로직을 만들어 봤다.

TimeZoneInfo tz = TimeZoneInfo.FindSystemTimeZoneById(openHour.Timezone); //저장된 타임존을 가져온다. America/Los_Angeles
var currentLocalTime = TimeZoneInfo.ConvertTimeFromUtc(current, tz); //식당의 위치에 localtime으로 바꾼다.
if(openHour.DayOfWeek == currentLocalTime.DayOfWeek) // 요일이 같은날이면
{
  var differntDay = (int)(currentLocalTime - openHour.TimeOfStartWork).TotalDays; //현재 로컬날짜와 디비에 잇는 workstart와 날자 차이를 계산한다.
  // 차이나는 날짜를 start에 더해준다. summertime인지 아닌지 알기 위해 그리고 현재 로컬 날짜가 이 더한 날짜 사이에잇는지 확인한다.
  var isCurrentlyOpen = Between(currentLocalTime, openHour.TimeOfStartWork.AddDays(differntDay), openHour.TimeOfEndWork.AddDays(differntDay));

  if(isCurrentlyOpen){
    Console.WriteLine("find openhour currently time:");
    item.IsOpen = true;
    break;
  }
}

private bool Between(DateTime input, DateTime sdate, DateTime edate)
{
  System.Console.WriteLine("input "+input);
  System.Console.WriteLine("sdate "+sdate);
  System.Console.WriteLine("edate "+edate);
  if(input >= sdate && input <= edate){
    return true;
  }
  return false;
}

gmt인 서버시간을 고객의 로컬시간으로 바꾸고 그 로컬시간이 기준시간(2020-01-01)로부터 몇일이 차이나는지 확인후 그 날짜만큼 식당 open시간에 더해준다.

그리고 현재 시간이 그 두 시간사이에 잇는지 확인하면 된다.

이렇게 하면 고객의 타임존과 상관없이 매번 고객의 로컬 시간으로 처리가 되서 쉽게 된다.

결론

프론트로 am/pm으로 입력받은걸 서버에서는 특정일(2020-01-01) 이후에 붙여서 datetime을 만든후 디비에 저장.

보여줄때는 hh:mm tt 를 이용하여 시간만 보여주면 되고

현재 시간 기준으로 open인지를 확인하려면 현재 gmt시간을 고객 시간대에 현지 시간(A)으로 바꾸고 . 이 현지 시간(A)이 기준일 부터 몇일이 지난건지 확인해서 workstart/workend에 추가해주면 식당의 오늘 오픈시간(daylight saving을 포함)을 알수있다.

이 오픈시간에 현지 시간(A)이 오픈된건지만 확인하면 된다.

모든걸 date로 처리하므로 스트링 파싱등이 필요가 없어지게 되어서 편해졋다.

teamsmiley's profile image

teamsmiley

2020-12-09 00:00

Read more posts by this author