iT邦幫忙

2022 iThome 鐵人賽

DAY 19
0
Software Development

戀戀 Elixir系列 第 19

十九. Dates and Time

  • 分享至 

  • xImage
  •  

Your librarian friend has asked you to extend her library software to automatically calculate late fees.

Her current system stores the exact date and time of a book checkout as an ISO8601 datetime string.
She runs a local library in a small town in Ghana, which uses the GMT timezone (UTC +0), doesn't use daylight saving time, and doesn't need to worry about other timezones.

1. Parse the stored datetimes

Implement the LibraryFees.datetime_from_string/1 function. It should take an ISO8601 datetime string as an argument, and return a NaiveDateTime struct.

2. Determine if a book was checked out before noon

If a book was checked out before noon, the reader has 28 days to return it. If it was checked out at or after noon, it's 29 days.

Implement the LibraryFees.before_noon?/1 function. It should take a NaiveDateTime struct and return a boolean.

3. Calculate the return date

Based on the checkout datetime, calculate the return date.

Implement the LibraryFees.return_date/1 function. It should take a NaiveDateTime struct and return a Date struct, either 28 or 29 days later.

4. Determine how late the return of the book was

The library has a flat rate for late returns. To be able to calculate the fee, we need to know how many days after the return date the book was actually returned.

Implement the LibraryFees.days_late/2 function. It should take a Date struct - the planned return datetime, and a NaiveDateTime struct - the actual return datetime.

If the actual return date is on an earlier or the same day as the planned return datetime, the function should return 0. Otherwise, the function should return the difference between those two dates in days.

The library tracks both the date and time of the actual return of the book for statistical purposes, but doesn't use the time when calculating late fees.

5. Determine if the book was returned on a Monday

The library has a special offer for returning books on Mondays.

Implement the LibraryFees.monday?/1 function. It should take a NaiveDateTime struct and return a boolean.

6. Calculate the late fee

Implement the LibraryFees.calculate_late_fee/3 function. It should take three arguments - two ISO8601 datetime strings, checkout datetime and actual return datetime, and the late fee for one day. It should return the total late fee according to how late the actual return of the book was.

Include the special Monday offer. If you return the book on Monday, your late fee is 50% off, rounded down.


https://exercism.org/tracks/elixir/exercises/library-fees

defmodule LibraryFees do
  @moduledoc """
  practice datetime
  """

  @monday 1
  @noon ~T[12:00:00]
  @original_return_days 28
  @extra_return_days @original_return_days + 1
  @discount_rate 0.5

  def datetime_from_string(string), do: string |> NaiveDateTime.from_iso8601!

  def before_noon?(datetime) do
    datetime
    |> NaiveDateTime.to_time
    |> Time.compare(@noon)
    |> Kernel.===(:lt)

    # datetime.hour < 12
  end

  def return_date(checkout_datetime) do
    return_days = if checkout_datetime |> before_noon?, do: @original_return_days, else: @extra_return_days

    checkout_datetime
    |> NaiveDateTime.to_date
    |> Date.add(return_days)
  end

  def days_late(planned_return_date, actual_return_datetime) do
    actual_return_date = actual_return_datetime |> NaiveDateTime.to_date
    is_late_for_return? = actual_return_date |> Date.compare(planned_return_date) |> Kernel.===(:gt)

    if is_late_for_return?, do: actual_return_date |> Date.diff(planned_return_date) |> abs, else: 0
  end

  def monday?(datetime) do
    datetime
    |> NaiveDateTime.to_date
    |> Date.day_of_week
    |> Kernel.===(@monday)
  end

  def calculate_late_fee(checkout_datetime, actual_return_datetime, rate) do
    planned_return_date = checkout_datetime |> datetime_from_string |> return_date
    actual_return_datetime_iso = actual_return_datetime |> datetime_from_string

    fee = days_late(planned_return_date, actual_return_datetime_iso) * rate

    if monday?(actual_return_datetime_iso), do: fee * @discount_rate |> floor, else: fee
  end
end

上一篇
十八. Bistrings
下一篇
二十. Access Behaviour
系列文
戀戀 Elixir30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言