-
Notifications
You must be signed in to change notification settings - Fork 1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Zoned date time #3
base: option-0-no-api
Are you sure you want to change the base?
Changes from all commits
23e33a7
89e4c02
4c379c1
d2eb50d
19e10a6
c9c2268
54a628c
20ce194
6baa03c
50af408
aa0836c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,35 +1,41 @@ | ||
package tw.joi.energy.config; | ||
|
||
import java.math.BigDecimal; | ||
import java.math.RoundingMode; | ||
import java.time.Instant; | ||
import java.util.ArrayList; | ||
import java.util.Comparator; | ||
import java.util.List; | ||
import java.time.Clock; | ||
import java.time.temporal.ChronoUnit; | ||
import java.util.Random; | ||
import java.util.stream.Stream; | ||
import tw.joi.energy.domain.ElectricityReading; | ||
|
||
public class ElectricityReadingsGenerator { | ||
|
||
public static List<ElectricityReading> generate(int number) { | ||
List<ElectricityReading> readings = new ArrayList<>(); | ||
Instant now = Instant.now(); | ||
BigDecimal previousReading = BigDecimal.ONE; | ||
Instant previousReadingTime = now.minusSeconds(2 * number * 60L); | ||
public static final double AVG_HOURLY_USAGE = 0.3; | ||
public static final double VARIANCE = 0.2; | ||
public static final double MIN_HOURLY_USAGE = AVG_HOURLY_USAGE - VARIANCE; | ||
public static final double MAX_HOURLY_USAGE = AVG_HOURLY_USAGE + VARIANCE; | ||
|
||
Random readingRandomiser = new Random(); | ||
private ElectricityReadingsGenerator() {} | ||
|
||
for (int i = 0; i < number; i++) { | ||
double positiveIncrement = Math.abs(readingRandomiser.nextGaussian()); | ||
BigDecimal currentReading = | ||
previousReading.add(BigDecimal.valueOf(positiveIncrement)).setScale(4, RoundingMode.CEILING); | ||
ElectricityReading electricityReading = | ||
new ElectricityReading(previousReadingTime.plusSeconds(i * 60L), currentReading); | ||
readings.add(electricityReading); | ||
previousReading = currentReading; | ||
} | ||
public static Stream<ElectricityReading> generateElectricityReadingStream(int days) { | ||
return generateElectricityReadingStream(Clock.systemDefaultZone(), BigDecimal.ZERO, days); | ||
} | ||
|
||
// we'll provide hourly readings for the specified number of days assuming 24 hours a day | ||
// we'll assume that a house consumes ca 2700 kWh a year, so about 0.3 kWh per hour | ||
|
||
readings.sort(Comparator.comparing(ElectricityReading::time)); | ||
return readings; | ||
// the assumed starting point is the time on the clock, the ending point 24 hours later - so for 1 day, we'll get 25 | ||
// readings | ||
public static Stream<ElectricityReading> generateElectricityReadingStream( | ||
Clock clock, BigDecimal initialReading, int days) { | ||
var now = clock.instant(); | ||
var readingRandomiser = new Random(); | ||
var seed = new ElectricityReading(now, initialReading); | ||
var lastTimeToBeSupplied = now.plus(days * 24L, ChronoUnit.HOURS); | ||
return Stream.iterate(seed, er -> !er.time().isAfter(lastTimeToBeSupplied), er -> { | ||
var hoursWorthOfEnergy = | ||
BigDecimal.valueOf(readingRandomiser.nextDouble(MIN_HOURLY_USAGE, MAX_HOURLY_USAGE)); | ||
return new ElectricityReading( | ||
er.time().plus(1, ChronoUnit.HOURS), er.readingInKwH().add(hoursWorthOfEnergy)); | ||
}); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,9 +1,16 @@ | ||
package tw.joi.energy.domain; | ||
|
||
import java.math.BigDecimal; | ||
import java.time.Clock; | ||
import java.time.Instant; | ||
|
||
/** | ||
* @param reading kWh | ||
* @param time point in time | ||
* @param readingInKwH energy consumed in total to this point in time in kWh | ||
*/ | ||
public record ElectricityReading(Instant time, BigDecimal reading) {} | ||
public record ElectricityReading(Instant time, BigDecimal readingInKwH) { | ||
|
||
public ElectricityReading(Clock clock, double readingInKwH) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this constructor meant to be for testing purposes (faking the current time, lighter syntax for the reading) or also for production usage? |
||
this(clock.instant(), BigDecimal.valueOf(readingInKwH)); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
package tw.joi.energy.domain; | ||
|
||
import java.math.BigDecimal; | ||
import java.time.DayOfWeek; | ||
|
||
public record PeakTimeMultiplier(DayOfWeek dayOfWeek, BigDecimal multiplier) {} |
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -1,64 +1,55 @@ | ||||||
package tw.joi.energy.domain; | ||||||
|
||||||
import java.io.*; | ||||||
import java.math.BigDecimal; | ||||||
import java.text.*; | ||||||
import java.time.DayOfWeek; | ||||||
import java.time.LocalDateTime; | ||||||
import java.util.List; | ||||||
import java.time.ZonedDateTime; | ||||||
import java.util.Collections; | ||||||
import java.util.HashMap; | ||||||
import java.util.Map; | ||||||
|
||||||
public class PricePlan { | ||||||
|
||||||
private String energySupplier; | ||||||
private String planName; | ||||||
private final String energySupplier; | ||||||
private final String planName; | ||||||
private final BigDecimal unitRate; // unit price per kWh | ||||||
private final List<PeakTimeMultiplier> peakTimeMultipliers; | ||||||
private final Map<DayOfWeek, BigDecimal> peakTimeMultipliers; | ||||||
|
||||||
public PricePlan(String planName, String energySupplier, BigDecimal unitRate) { | ||||||
this.planName = planName; | ||||||
this.energySupplier = energySupplier; | ||||||
this.unitRate = unitRate; | ||||||
this.peakTimeMultipliers = Collections.emptyMap(); | ||||||
} | ||||||
|
||||||
public PricePlan( | ||||||
String planName, String energySupplier, BigDecimal unitRate, List<PeakTimeMultiplier> peakTimeMultipliers) { | ||||||
String planName, | ||||||
String energySupplier, | ||||||
BigDecimal unitRate, | ||||||
Map<DayOfWeek, BigDecimal> peakTimeMultipliers) { | ||||||
this.planName = planName; | ||||||
this.energySupplier = energySupplier; | ||||||
this.unitRate = unitRate; | ||||||
this.peakTimeMultipliers = peakTimeMultipliers; | ||||||
this.peakTimeMultipliers = Collections.unmodifiableMap(new HashMap<>(peakTimeMultipliers)); | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
Credit goes to IntelliJ for that suggestion... |
||||||
} | ||||||
|
||||||
public String getEnergySupplier() { | ||||||
return energySupplier; | ||||||
} | ||||||
|
||||||
public void setEnergySupplier(String supplierName) { | ||||||
this.energySupplier = supplierName; | ||||||
} | ||||||
|
||||||
public String getPlanName() { | ||||||
return planName; | ||||||
} | ||||||
|
||||||
public void setPlanName(String name) { | ||||||
this.planName = name; | ||||||
} | ||||||
|
||||||
public BigDecimal getUnitRate() { | ||||||
return unitRate; | ||||||
} | ||||||
|
||||||
public BigDecimal getPrice(LocalDateTime dateTime) { | ||||||
public BigDecimal getPrice(ZonedDateTime dateTime) { | ||||||
return unitRate; | ||||||
} | ||||||
|
||||||
@Override | ||||||
public String toString() { | ||||||
return "Name: '" + planName + "', Unit Rate: " + unitRate + ", Supplier: '" + energySupplier + "'"; | ||||||
} | ||||||
|
||||||
static class PeakTimeMultiplier { | ||||||
|
||||||
DayOfWeek dayOfWeek; | ||||||
BigDecimal multiplier; | ||||||
|
||||||
public PeakTimeMultiplier(DayOfWeek dayOfWeek, BigDecimal multiplier) { | ||||||
this.dayOfWeek = dayOfWeek; | ||||||
this.multiplier = multiplier; | ||||||
} | ||||||
} | ||||||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure I buy returning a stream here. The implementation doesn't look much simpler, and every single caller wants a
List
instead of aStream
.The name also adds a lot of stutter (unless every caller switches to a static import).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd recommend the static import 😄 which was sort of my assumption anyway.
Lets think a bit more about streams - they're trivially convertible to lists anyway. To be honest, the functions also need some more possible parameters - eg the interval between the readings to generate and the function to generate the values. I hadn't quite finished removing all dependencies on hidden state such as Random...