Skip to content
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

Improved datetime unit transformer shortcuts #316

Merged
merged 20 commits into from
May 14, 2019

Conversation

crupley
Copy link
Contributor

@crupley crupley commented May 13, 2019

Related issues
Improved datetime unit transformer shortcuts #315

Describe the proposed solution
Enhanced RichDate and RichDateTime to allow conversion to various time periods using a common class. Each now supports a toTimePeriod method which can convert to any of the current TimePeriods:

TimePeriod.DayOfMonth
TimePeriod.DayOfWeek
TimePeriod.DayOfYear
TimePeriod.HourOfDay
TimePeriod.MonthOfYear
TimePeriod.WeekOfMonth
TimePeriod.WeekOfYear

Describe alternatives you've considered
There are many other potential values that could be extracted from the datetime, but I stuck to only those defined in the TimePeriod enum.

Additional context

@codecov
Copy link

codecov bot commented May 13, 2019

Codecov Report

Merging #316 into master will increase coverage by 1.3%.
The diff coverage is 16.66%.

Impacted file tree graph

@@            Coverage Diff            @@
##           master     #316     +/-   ##
=========================================
+ Coverage   80.89%   82.19%   +1.3%     
=========================================
  Files         325      327      +2     
  Lines       10581    10593     +12     
  Branches      349      550    +201     
=========================================
+ Hits         8559     8707    +148     
+ Misses       2022     1886    -136
Impacted Files Coverage Δ
...salesforce/op/stages/impl/feature/TimePeriod.scala 0% <0%> (ø)
...op/stages/impl/feature/TimePeriodTransformer.scala 100% <100%> (ø)
.../scala/com/salesforce/op/dsl/RichDateFeature.scala 94.44% <50%> (-5.56%) ⬇️
...alesforce/op/cli/gen/templates/SimpleProject.scala 0% <0%> (-100%) ⬇️
...om/salesforce/op/local/OpWorkflowRunnerLocal.scala 0% <0%> (-100%) ⬇️
.../scala/com/salesforce/op/cli/gen/ProblemKind.scala 0% <0%> (-100%) ⬇️
...cala/com/salesforce/op/cli/gen/FileInProject.scala 0% <0%> (-100%) ⬇️
...in/scala/com/salesforce/op/cli/CommandParser.scala 0% <0%> (-98.12%) ⬇️
...com/salesforce/op/local/OpWorkflowModelLocal.scala 0% <0%> (-97.37%) ⬇️
...cala/com/salesforce/op/cli/gen/ProblemSchema.scala 0% <0%> (-96.56%) ⬇️
... and 68 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 9d01538...00b38cb. Read the comment docs.

* @return Integer feature of time period value
*/
def toTimePeriod(period: TimePeriod): FeatureLike[Integral] = {
val periodFun: Long => Int = period match {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lets add a concrete transformer class that extends UnaryTransformer instead of using UnaryLambdaTransformer

)
}

def toDayOfMonth(): FeatureLike[Integral] = toTimePeriod(TimePeriod.DayOfMonth)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there much value of having these methods? let's just have def toTimePeriod(period: TimePeriod) and that way you wont need this abstract class bu simply add toTimePeriod to both RichDateTimeFeature and RichDateFeature.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think so. As a user, I would much prefer to use these shortcuts and likely not use the time period shortcuts at all.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Once introduced, we would have to maintain them ;) and each time a new entry in enum is added we would need to add a new method. that's why I just prefer a single method with an enum argument.

import org.scalatest.junit.JUnitRunner

@RunWith(classOf[JUnitRunner])
class RichDateFeatureTest extends FlatSpec with TestSparkContext {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

once you have a concrete transformer, please use OpTransformerSpec to test it

Copy link
Collaborator

@tovbinm tovbinm left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

some minor comments, otherwise lgtm

@@ -0,0 +1,41 @@
package com.salesforce.op.stages.impl.feature
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please add license header

)(
implicit override val tti: TypeTag[I]
) extends UnaryTransformer[I, Integral](operationName = "dateToTimePeriod", uid = uid){
val periodFun: Long => Int = period match {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just make this a regular function def periodConversion(time: Long): Int = period match { ... }

@tovbinm
Copy link
Collaborator

tovbinm commented May 14, 2019

@crupley fyi, we also have DateList, DateTimeList, DateMap and DateTimeMap feature types. are you planning to add similar shortcuts to those in the following PRs?

@crupley
Copy link
Contributor Author

crupley commented May 14, 2019

Thanks for pointing that out; yes, I can add that in a new PR

case TimePeriod.HourOfDay => new JDateTime(t, DateTimeUtils.DefaultTimeZone).hourOfDay.get
case TimePeriod.MonthOfYear => new JDateTime(t, DateTimeUtils.DefaultTimeZone).monthOfYear.get
case TimePeriod.WeekOfMonth =>
val dt = new JDateTime(t, DateTimeUtils.DefaultTimeZone)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

JDateTime(t, DateTimeUtils.DefaultTimeZone) is repeated on every case. Let us pull it before the pattern match.

)(
implicit override val tti: TypeTag[I]
) extends UnaryTransformer[I, Integral](operationName = "dateToTimePeriod", uid = uid){
def periodFun(t: Long): Int = period match {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

would it make sense to use OOP and put

sealed abstract class TimePeriod extends EnumEntry with Serializable {
  def periodFun(t: Long): Int
}

case object Blah extends TimePeriod {
    override def periodFun(t: Long): Int = ???
}

and call period.periodFun here

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

put logic into enum? I am not a big fan of this pattern.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good idea; let me try it

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Eliminates the case matching or having to pass a trait around with the conversion function in it. What do you think of the implementation, @tovbinm?

case object MonthOfYear extends TimePeriod
case object WeekOfMonth extends TimePeriod
case object WeekOfYear extends TimePeriod
case object DayOfMonth extends TimePeriod { def extractFromTime(t: Long): Int = longToDateTime(t).dayOfMonth.get }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's easier to read if the function definition is after a line break.

case TimePeriod.MonthOfYear => Array(Integral(3), Integral(11), Integral(3), Integral.empty, Integral(4))
case TimePeriod.WeekOfMonth => Array(Integral(2), Integral(1), Integral(1), Integral.empty, Integral(4))
case TimePeriod.WeekOfYear => Array(Integral(11), Integral(45), Integral(10), Integral.empty, Integral(18))
case _ => throw new Exception(s"Unexpected TimePeriod encountered, $tp")
Copy link
Collaborator

@tovbinm tovbinm May 14, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in tests instead of throw new Exception(s"Unexpected TimePeriod encountered, $tp") do fail(s"Unexpected TimePeriod encountered, $tp")

@tovbinm tovbinm merged commit 18a9243 into salesforce:master May 14, 2019
@crupley crupley deleted the cr/timeperiod branch May 14, 2019 22:58
This was referenced Jul 10, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants