Reputation: 99794
Given an amount of days, say 25, convert it into a duration text such as "3 Weeks, 4 Days"
C# and F# solutions would both be great if the F# variation offers any improvement over C#.
Edit: The solution should expand past weeks to include months and years. Bonus points for including centuries and so on. Extra bonus if it is somewhat configurable, meaning you can tell the method to exclude the normalization of weeks.
Upvotes: 3
Views: 1504
Reputation: 391
This is a recursive solution. Note that a duration only really makes sense measured against a particular point in time on a given calendar because month and year lengths vary. But here is a simple solution assuming fixed lengths:
let divmod n m = n / m, n % m
let units = [
("Centuries", TimeSpan.TicksPerDay * 365L * 100L );
("Years", TimeSpan.TicksPerDay * 365L);
("Weeks", TimeSpan.TicksPerDay * 7L);
("Days", TimeSpan.TicksPerDay)
]
let duration days =
let rec duration' ticks units acc =
match units with
| [] -> acc
| (u::us) ->
let (wholeUnits, ticksRemaining) = divmod ticks (snd u)
duration' ticksRemaining us (((fst u), wholeUnits) :: acc)
duration' (TimeSpan.FromDays(float days).Ticks) units []
Upvotes: 2
Reputation: 118895
Here's an F# version based on the previously posted C# version. The main difference is it's applicative rather than imperative (no mutable variables).
#light
let conversions = [|
365, "Year", "Years"
30, "Month", "Months"
7, "Week", "Weeks"
1, "Day", "Days" |]
let ToDuration numDays =
conversions
|> Array.fold_left (fun (remainDays,results) (n,sing,plur) ->
let count = remainDays / n
if count >= 1 then
remainDays - (count * n),
(sprintf "%d %s" count (if count=1 then sing else plur)) :: results
else
remainDays, results
) (numDays,[])
|> snd |> (fun rs -> System.String.Join(", ", List.rev rs |> List.to_array))
printfn "%s" (ToDuration 1008)
Upvotes: 0
Reputation: 99794
public class UnitOfMeasure {
public UnitOfMeasure(string name, int value) {
Name = name;
Value = value;
}
public string Name { get; set; }
public int Value { get; set; }
public static UnitOfMeasure[] All = new UnitOfMeasure[] {
new UnitOfMeasure("Year", 356),
new UnitOfMeasure("Month", 30),
new UnitOfMeasure("Week", 7),
new UnitOfMeasure("Day", 1)
};
public static string ConvertToDuration(int days) {
List<string> results = new List<string>();
for (int i = 0; i < All.Length; i++) {
int count = days / All[i].Value;
if (count >= 1) {
results.Add((count + " " + All[i].Name) + (count == 1 ? string.Empty : "s"));
days -= count * All[i].Value;
}
}
return string.Join(", ", results.ToArray());
}
}
Upvotes: 0