Last active
August 29, 2015 13:56
-
-
Save jodastephen/9057131 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# HG changeset patch | |
# User scolebourne | |
# Date 1394126180 0 | |
# Node ID 5fa8324688fe78e43799053eab88e3e643e1d34b | |
# Parent 39a459cf1bcb80922c4f6b04a46743cd8baf824e | |
JDK-8035099 - LocalTime.with | |
diff --git a/src/share/classes/java/time/LocalTime.java b/src/share/classes/java/time/LocalTime.java | |
--- a/src/share/classes/java/time/LocalTime.java | |
+++ b/src/share/classes/java/time/LocalTime.java | |
@@ -838,9 +838,9 @@ | |
case NANO_OF_SECOND: return withNano((int) newValue); | |
case NANO_OF_DAY: return LocalTime.ofNanoOfDay(newValue); | |
case MICRO_OF_SECOND: return withNano((int) newValue * 1000); | |
- case MICRO_OF_DAY: return plusNanos((newValue - toNanoOfDay() / 1000) * 1000); | |
+ case MICRO_OF_DAY: return LocalTime.ofNanoOfDay(newValue * 1000); | |
case MILLI_OF_SECOND: return withNano((int) newValue * 1000_000); | |
- case MILLI_OF_DAY: return plusNanos((newValue - toNanoOfDay() / 1000_000) * 1000_000); | |
+ case MILLI_OF_DAY: return LocalTime.ofNanoOfDay(newValue * 1000_000); | |
case SECOND_OF_MINUTE: return withSecond((int) newValue); | |
case SECOND_OF_DAY: return plusSeconds(newValue - toSecondOfDay()); | |
case MINUTE_OF_HOUR: return withMinute((int) newValue); | |
diff --git a/test/java/time/tck/java/time/TCKLocalTime.java b/test/java/time/tck/java/time/TCKLocalTime.java | |
--- a/test/java/time/tck/java/time/TCKLocalTime.java | |
+++ b/test/java/time/tck/java/time/TCKLocalTime.java | |
@@ -88,11 +88,10 @@ | |
import static java.time.temporal.ChronoUnit.YEARS; | |
import static org.testng.Assert.assertEquals; | |
import static org.testng.Assert.assertNotNull; | |
+import static org.testng.Assert.assertSame; | |
import static org.testng.Assert.assertTrue; | |
import static org.testng.Assert.fail; | |
-import java.io.ByteArrayOutputStream; | |
-import java.io.DataOutputStream; | |
import java.time.Clock; | |
import java.time.DateTimeException; | |
import java.time.Duration; | |
@@ -120,6 +119,7 @@ | |
import java.time.temporal.TemporalQuery; | |
import java.time.temporal.TemporalUnit; | |
import java.time.temporal.UnsupportedTemporalTypeException; | |
+import java.time.temporal.ValueRange; | |
import java.util.ArrayList; | |
import java.util.Arrays; | |
import java.util.EnumSet; | |
@@ -760,7 +760,7 @@ | |
} | |
//----------------------------------------------------------------------- | |
- // with() | |
+ // with(TemporalAdjuster) | |
//----------------------------------------------------------------------- | |
@Test | |
public void test_with_adjustment() { | |
@@ -780,6 +780,331 @@ | |
} | |
//----------------------------------------------------------------------- | |
+ // with(TemporalField, long) | |
+ //----------------------------------------------------------------------- | |
+ private long[] testPoints(long max) { | |
+ long[] points = new long[9]; | |
+ points[0] = 0; | |
+ points[1] = 1; | |
+ points[2] = 2; | |
+ points[3] = max / 7; | |
+ points[4] = (max / 7) * 2; | |
+ points[5] = (max / 2); | |
+ points[6] = (max / 7) * 6;; | |
+ points[7] = max - 2; | |
+ points[8] = max - 1; | |
+ return points; | |
+ } | |
+ | |
+ // Returns a {@code LocalTime} with the specified nano-of-second. | |
+ // The hour, minute and second will be unchanged. | |
+ @Test | |
+ public void test_with_longTemporalField_nanoOfSecond() { | |
+ for (long i : testPoints(1_000_000_000L)) { | |
+ LocalTime test = TEST_12_30_40_987654321.with(NANO_OF_SECOND, i); | |
+ assertEquals(test.get(NANO_OF_SECOND), i); | |
+ assertEquals(test.get(HOUR_OF_DAY), TEST_12_30_40_987654321.get(HOUR_OF_DAY)); | |
+ assertEquals(test.get(MINUTE_OF_HOUR), TEST_12_30_40_987654321.get(MINUTE_OF_HOUR)); | |
+ assertEquals(test.get(SECOND_OF_MINUTE), TEST_12_30_40_987654321.get(SECOND_OF_MINUTE)); | |
+ } | |
+ } | |
+ | |
+ // Returns a {@code LocalTime} with the specified nano-of-day. | |
+ // This completely replaces the time and is equivalent to {@link #ofNanoOfDay(long)}. | |
+ @Test | |
+ public void test_with_longTemporalField_nanoOfDay() { | |
+ for (long i : testPoints(86_400_000_000_000L)) { | |
+ LocalTime test = TEST_12_30_40_987654321.with(NANO_OF_DAY, i); | |
+ assertEquals(test, LocalTime.ofNanoOfDay(i)); | |
+ } | |
+ } | |
+ | |
+ // Returns a {@code LocalTime} with the nano-of-second replaced by the specified | |
+ // micro-of-second multiplied by 1,000. | |
+ // The hour, minute and second will be unchanged. | |
+ @Test | |
+ public void test_with_longTemporalField_microOfSecond() { | |
+ for (long i : testPoints(1_000_000L)) { | |
+ LocalTime test = TEST_12_30_40_987654321.with(MICRO_OF_SECOND, i); | |
+ assertEquals(test.get(NANO_OF_SECOND), i * 1_000); | |
+ assertEquals(test.get(HOUR_OF_DAY), TEST_12_30_40_987654321.get(HOUR_OF_DAY)); | |
+ assertEquals(test.get(MINUTE_OF_HOUR), TEST_12_30_40_987654321.get(MINUTE_OF_HOUR)); | |
+ assertEquals(test.get(SECOND_OF_MINUTE), TEST_12_30_40_987654321.get(SECOND_OF_MINUTE)); | |
+ } | |
+ } | |
+ | |
+ // Returns a {@code LocalTime} with the specified micro-of-day. | |
+ // This completely replaces the time and is equivalent to using {@link #ofNanoOfDay(long)} | |
+ // with the micro-of-day multiplied by 1,000. | |
+ @Test | |
+ public void test_with_longTemporalField_microOfDay() { | |
+ for (long i : testPoints(86_400_000_000L)) { | |
+ LocalTime test = TEST_12_30_40_987654321.with(MICRO_OF_DAY, i); | |
+ assertEquals(test, LocalTime.ofNanoOfDay(i * 1000)); | |
+ } | |
+ } | |
+ | |
+ // Returns a {@code LocalTime} with the nano-of-second replaced by the specified | |
+ // milli-of-second multiplied by 1,000,000. | |
+ // The hour, minute and second will be unchanged. | |
+ @Test | |
+ public void test_with_longTemporalField_milliOfSecond() { | |
+ for (long i : testPoints(1_000L)) { | |
+ LocalTime test = TEST_12_30_40_987654321.with(MILLI_OF_SECOND, i); | |
+ assertEquals(test.get(NANO_OF_SECOND), i * 1_000_000); | |
+ assertEquals(test.get(HOUR_OF_DAY), TEST_12_30_40_987654321.get(HOUR_OF_DAY)); | |
+ assertEquals(test.get(MINUTE_OF_HOUR), TEST_12_30_40_987654321.get(MINUTE_OF_HOUR)); | |
+ assertEquals(test.get(SECOND_OF_MINUTE), TEST_12_30_40_987654321.get(SECOND_OF_MINUTE)); | |
+ } | |
+ } | |
+ | |
+ // Returns a {@code LocalTime} with the specified milli-of-day. | |
+ // This completely replaces the time and is equivalent to using {@link #ofNanoOfDay(long)} | |
+ // with the milli-of-day multiplied by 1,000,000. | |
+ @Test | |
+ public void test_with_longTemporalField_milliOfDay() { | |
+ for (long i : testPoints(86_400_000L)) { | |
+ LocalTime test = TEST_12_30_40_987654321.with(MILLI_OF_DAY, i); | |
+ assertEquals(test, LocalTime.ofNanoOfDay(i * 1_000_000)); | |
+ } | |
+ } | |
+ | |
+ // Returns a {@code LocalTime} with the specified second-of-minute. | |
+ // The hour, minute and nano-of-second will be unchanged. | |
+ @Test | |
+ public void test_with_longTemporalField_secondOfMinute() { | |
+ for (long i : testPoints(60L)) { | |
+ LocalTime test = TEST_12_30_40_987654321.with(SECOND_OF_MINUTE, i); | |
+ assertEquals(test.get(SECOND_OF_MINUTE), i); | |
+ assertEquals(test.get(HOUR_OF_DAY), TEST_12_30_40_987654321.get(HOUR_OF_DAY)); | |
+ assertEquals(test.get(MINUTE_OF_HOUR), TEST_12_30_40_987654321.get(MINUTE_OF_HOUR)); | |
+ assertEquals(test.get(NANO_OF_SECOND), TEST_12_30_40_987654321.get(NANO_OF_SECOND)); | |
+ } | |
+ } | |
+ | |
+ // Returns a {@code LocalTime} with the specified second-of-day. | |
+ // The nano-of-second will be unchanged. | |
+ @Test | |
+ public void test_with_longTemporalField_secondOfDay() { | |
+ for (long i : testPoints(24 * 60 * 60)) { | |
+ LocalTime test = TEST_12_30_40_987654321.with(SECOND_OF_DAY, i); | |
+ assertEquals(test.get(SECOND_OF_DAY), i); | |
+ assertEquals(test.get(NANO_OF_SECOND), TEST_12_30_40_987654321.get(NANO_OF_SECOND)); | |
+ } | |
+ } | |
+ | |
+ // Returns a {@code LocalTime} with the specified minute-of-hour. | |
+ // The hour, second-of-minute and nano-of-second will be unchanged. | |
+ @Test | |
+ public void test_with_longTemporalField_minuteOfHour() { | |
+ for (long i : testPoints(60)) { | |
+ LocalTime test = TEST_12_30_40_987654321.with(MINUTE_OF_HOUR, i); | |
+ assertEquals(test.get(MINUTE_OF_HOUR), i); | |
+ assertEquals(test.get(HOUR_OF_DAY), TEST_12_30_40_987654321.get(HOUR_OF_DAY)); | |
+ assertEquals(test.get(SECOND_OF_MINUTE), TEST_12_30_40_987654321.get(SECOND_OF_MINUTE)); | |
+ assertEquals(test.get(NANO_OF_SECOND), TEST_12_30_40_987654321.get(NANO_OF_SECOND)); | |
+ } | |
+ } | |
+ | |
+ // Returns a {@code LocalTime} with the specified minute-of-day. | |
+ // The second-of-minute and nano-of-second will be unchanged. | |
+ @Test | |
+ public void test_with_longTemporalField_minuteOfDay() { | |
+ for (long i : testPoints(24 * 60)) { | |
+ LocalTime test = TEST_12_30_40_987654321.with(MINUTE_OF_DAY, i); | |
+ assertEquals(test.get(MINUTE_OF_DAY), i); | |
+ assertEquals(test.get(SECOND_OF_MINUTE), TEST_12_30_40_987654321.get(SECOND_OF_MINUTE)); | |
+ assertEquals(test.get(NANO_OF_SECOND), TEST_12_30_40_987654321.get(NANO_OF_SECOND)); | |
+ } | |
+ } | |
+ | |
+ // Returns a {@code LocalTime} with the specified hour-of-am-pm. | |
+ // The AM/PM, minute-of-hour, second-of-minute and nano-of-second will be unchanged. | |
+ @Test | |
+ public void test_with_longTemporalField_hourOfAmPm() { | |
+ for (int i = 0; i < 12; i++) { | |
+ LocalTime test = TEST_12_30_40_987654321.with(HOUR_OF_AMPM, i); | |
+ assertEquals(test.get(HOUR_OF_AMPM), i); | |
+ assertEquals(test.get(AMPM_OF_DAY), TEST_12_30_40_987654321.get(AMPM_OF_DAY)); | |
+ assertEquals(test.get(MINUTE_OF_HOUR), TEST_12_30_40_987654321.get(MINUTE_OF_HOUR)); | |
+ assertEquals(test.get(SECOND_OF_MINUTE), TEST_12_30_40_987654321.get(SECOND_OF_MINUTE)); | |
+ assertEquals(test.get(NANO_OF_SECOND), TEST_12_30_40_987654321.get(NANO_OF_SECOND)); | |
+ } | |
+ } | |
+ | |
+ // Returns a {@code LocalTime} with the specified clock-hour-of-am-pm. | |
+ // The AM/PM, minute-of-hour, second-of-minute and nano-of-second will be unchanged. | |
+ @Test | |
+ public void test_with_longTemporalField_clockHourOfAmPm() { | |
+ for (int i = 1; i <= 12; i++) { | |
+ LocalTime test = TEST_12_30_40_987654321.with(CLOCK_HOUR_OF_AMPM, i); | |
+ assertEquals(test.get(CLOCK_HOUR_OF_AMPM), i); | |
+ assertEquals(test.get(AMPM_OF_DAY), TEST_12_30_40_987654321.get(AMPM_OF_DAY)); | |
+ assertEquals(test.get(MINUTE_OF_HOUR), TEST_12_30_40_987654321.get(MINUTE_OF_HOUR)); | |
+ assertEquals(test.get(SECOND_OF_MINUTE), TEST_12_30_40_987654321.get(SECOND_OF_MINUTE)); | |
+ assertEquals(test.get(NANO_OF_SECOND), TEST_12_30_40_987654321.get(NANO_OF_SECOND)); | |
+ } | |
+ } | |
+ | |
+ // Returns a {@code LocalTime} with the specified hour-of-day. | |
+ // The minute-of-hour, second-of-minute and nano-of-second will be unchanged. | |
+ @Test | |
+ public void test_with_longTemporalField_hourOfDay() { | |
+ for (int i = 0; i < 24; i++) { | |
+ LocalTime test = TEST_12_30_40_987654321.with(HOUR_OF_DAY, i); | |
+ assertEquals(test.get(HOUR_OF_DAY), i); | |
+ assertEquals(test.get(MINUTE_OF_HOUR), TEST_12_30_40_987654321.get(MINUTE_OF_HOUR)); | |
+ assertEquals(test.get(SECOND_OF_MINUTE), TEST_12_30_40_987654321.get(SECOND_OF_MINUTE)); | |
+ assertEquals(test.get(NANO_OF_SECOND), TEST_12_30_40_987654321.get(NANO_OF_SECOND)); | |
+ } | |
+ } | |
+ | |
+ // Returns a {@code LocalTime} with the specified clock-hour-of-day. | |
+ // The minute-of-hour, second-of-minute and nano-of-second will be unchanged. | |
+ @Test | |
+ public void test_with_longTemporalField_clockHourOfDay() { | |
+ for (int i = 1; i <= 24; i++) { | |
+ LocalTime test = TEST_12_30_40_987654321.with(CLOCK_HOUR_OF_DAY, i); | |
+ assertEquals(test.get(CLOCK_HOUR_OF_DAY), i); | |
+ assertEquals(test.get(MINUTE_OF_HOUR), TEST_12_30_40_987654321.get(MINUTE_OF_HOUR)); | |
+ assertEquals(test.get(SECOND_OF_MINUTE), TEST_12_30_40_987654321.get(SECOND_OF_MINUTE)); | |
+ assertEquals(test.get(NANO_OF_SECOND), TEST_12_30_40_987654321.get(NANO_OF_SECOND)); | |
+ } | |
+ } | |
+ | |
+ // Returns a {@code LocalTime} with the specified AM/PM. | |
+ // The hour-of-am-pm, minute-of-hour, second-of-minute and nano-of-second will be unchanged. | |
+ @Test | |
+ public void test_with_longTemporalField_amPmOfDay() { | |
+ for (int i = 0; i <= 1; i++) { | |
+ LocalTime test = TEST_12_30_40_987654321.with(AMPM_OF_DAY, i); | |
+ assertEquals(test.get(AMPM_OF_DAY), i); | |
+ assertEquals(test.get(HOUR_OF_AMPM), TEST_12_30_40_987654321.get(HOUR_OF_AMPM)); | |
+ assertEquals(test.get(MINUTE_OF_HOUR), TEST_12_30_40_987654321.get(MINUTE_OF_HOUR)); | |
+ assertEquals(test.get(SECOND_OF_MINUTE), TEST_12_30_40_987654321.get(SECOND_OF_MINUTE)); | |
+ assertEquals(test.get(NANO_OF_SECOND), TEST_12_30_40_987654321.get(NANO_OF_SECOND)); | |
+ } | |
+ } | |
+ | |
+ // The supported fields behave as follows... | |
+ // In all cases, if the new value is outside the valid range of values for the field | |
+ // then a {@code DateTimeException} will be thrown. | |
+ @DataProvider(name = "withTemporalField_outOfRange") | |
+ Object[][] data_withTemporalField_outOfRange() { | |
+ return new Object[][] { | |
+ {NANO_OF_SECOND, time(0, 0, 0, 0), NANO_OF_SECOND.range().getMinimum() - 1}, | |
+ {NANO_OF_SECOND, time(0, 0, 0, 0), NANO_OF_SECOND.range().getMaximum() + 1}, | |
+ | |
+ {NANO_OF_DAY, time(0, 0, 0, 0), NANO_OF_DAY.range().getMinimum() - 1}, | |
+ {NANO_OF_DAY, time(0, 0, 0, 0), NANO_OF_DAY.range().getMaximum() + 1}, | |
+ | |
+ {MICRO_OF_SECOND, time(0, 0, 0, 0), MICRO_OF_SECOND.range().getMinimum() - 1}, | |
+ {MICRO_OF_SECOND, time(0, 0, 0, 0), MICRO_OF_SECOND.range().getMaximum() + 1}, | |
+ | |
+ {MICRO_OF_DAY, time(0, 0, 0, 0), MICRO_OF_DAY.range().getMinimum() - 1}, | |
+ {MICRO_OF_DAY, time(0, 0, 0, 0), MICRO_OF_DAY.range().getMaximum() + 1}, | |
+ | |
+ {MILLI_OF_SECOND, time(0, 0, 0, 0), MILLI_OF_SECOND.range().getMinimum() - 1}, | |
+ {MILLI_OF_SECOND, time(0, 0, 0, 0), MILLI_OF_SECOND.range().getMaximum() + 1}, | |
+ | |
+ {MILLI_OF_DAY, time(0, 0, 0, 0), MILLI_OF_DAY.range().getMinimum() - 1}, | |
+ {MILLI_OF_DAY, time(0, 0, 0, 0), MILLI_OF_DAY.range().getMaximum() + 1}, | |
+ | |
+ {SECOND_OF_MINUTE, time(0, 0, 0, 0), SECOND_OF_MINUTE.range().getMinimum() - 1}, | |
+ {SECOND_OF_MINUTE, time(0, 0, 0, 0), SECOND_OF_MINUTE.range().getMaximum() + 1}, | |
+ | |
+ {SECOND_OF_DAY, time(0, 0, 0, 0), SECOND_OF_DAY.range().getMinimum() - 1}, | |
+ {SECOND_OF_DAY, time(0, 0, 0, 0), SECOND_OF_DAY.range().getMaximum() + 1}, | |
+ | |
+ {MINUTE_OF_HOUR, time(0, 0, 0, 0), MINUTE_OF_HOUR.range().getMinimum() - 1}, | |
+ {MINUTE_OF_HOUR, time(0, 0, 0, 0), MINUTE_OF_HOUR.range().getMaximum() + 1}, | |
+ | |
+ {MINUTE_OF_DAY, time(0, 0, 0, 0), MINUTE_OF_DAY.range().getMinimum() - 1}, | |
+ {MINUTE_OF_DAY, time(0, 0, 0, 0), MINUTE_OF_DAY.range().getMaximum() + 1}, | |
+ | |
+ {HOUR_OF_AMPM, time(0, 0, 0, 0), HOUR_OF_AMPM.range().getMinimum() - 1}, | |
+ {HOUR_OF_AMPM, time(0, 0, 0, 0), HOUR_OF_AMPM.range().getMaximum() + 1}, | |
+ | |
+ {CLOCK_HOUR_OF_AMPM, time(0, 0, 0, 0), CLOCK_HOUR_OF_AMPM.range().getMinimum() - 1}, | |
+ {CLOCK_HOUR_OF_AMPM, time(0, 0, 0, 0), CLOCK_HOUR_OF_AMPM.range().getMaximum() + 1}, | |
+ | |
+ {HOUR_OF_DAY, time(0, 0, 0, 0), HOUR_OF_DAY.range().getMinimum() - 1}, | |
+ {HOUR_OF_DAY, time(0, 0, 0, 0), HOUR_OF_DAY.range().getMaximum() + 1}, | |
+ | |
+ {CLOCK_HOUR_OF_DAY, time(0, 0, 0, 0), CLOCK_HOUR_OF_DAY.range().getMinimum() - 1}, | |
+ {CLOCK_HOUR_OF_DAY, time(0, 0, 0, 0), CLOCK_HOUR_OF_DAY.range().getMaximum() + 1}, | |
+ | |
+ {AMPM_OF_DAY, time(0, 0, 0, 0), AMPM_OF_DAY.range().getMinimum() - 1}, | |
+ {AMPM_OF_DAY, time(0, 0, 0, 0), AMPM_OF_DAY.range().getMaximum() + 1}, | |
+ }; | |
+ } | |
+ | |
+ @Test(dataProvider = "withTemporalField_outOfRange") | |
+ public void test_with_longTemporalField_invalid(TemporalField field, LocalTime base, long newValue) { | |
+ try { | |
+ base.with(field, newValue); | |
+ fail("Field should not be allowed " + field); | |
+ } catch (DateTimeException ex) { | |
+ // expected | |
+ } | |
+ } | |
+ | |
+ // All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}. | |
+ @Test(expectedExceptions=UnsupportedTemporalTypeException.class) | |
+ public void test_with_longTemporalField_otherChronoField() { | |
+ TEST_12_30_40_987654321.with(ChronoField.DAY_OF_MONTH, 1); | |
+ } | |
+ | |
+ // If the field is not a {@code ChronoField}, then the result of this method | |
+ // is obtained by invoking {@code TemporalField.adjustInto(Temporal, long)} | |
+ // passing {@code this} as the argument. | |
+ @Test | |
+ public void test_with_longTemporalField_notChronoField() { | |
+ final LocalTime result = LocalTime.of(12, 30); | |
+ final LocalTime base = LocalTime.of(15, 45); | |
+ TemporalField field = new TemporalField() { | |
+ public ValueRange rangeRefinedBy(TemporalAccessor temporal) { | |
+ throw new UnsupportedOperationException(); | |
+ } | |
+ public ValueRange range() { | |
+ return null; | |
+ } | |
+ public boolean isTimeBased() { | |
+ throw new UnsupportedOperationException(); | |
+ } | |
+ public boolean isSupportedBy(TemporalAccessor temporal) { | |
+ throw new UnsupportedOperationException(); | |
+ } | |
+ public boolean isDateBased() { | |
+ throw new UnsupportedOperationException(); | |
+ } | |
+ public TemporalUnit getRangeUnit() { | |
+ throw new UnsupportedOperationException(); | |
+ } | |
+ public long getFrom(TemporalAccessor temporal) { | |
+ throw new UnsupportedOperationException(); | |
+ } | |
+ public TemporalUnit getBaseUnit() { | |
+ throw new UnsupportedOperationException(); | |
+ } | |
+ public <R extends Temporal> R adjustInto(R temporal, long newValue) { | |
+ assertEquals(temporal, base); | |
+ assertEquals(newValue, 12L); | |
+ @SuppressWarnings("unchecked") | |
+ R r = (R) result; | |
+ return r; | |
+ } | |
+ }; | |
+ LocalTime test = base.with(field, 12L); | |
+ assertSame(test, result); | |
+ } | |
+ | |
+ @Test(expectedExceptions=NullPointerException.class) | |
+ public void test_with_longTemporalField_null() { | |
+ TEST_12_30_40_987654321.with((TemporalField) null, 1); | |
+ } | |
+ | |
+ //----------------------------------------------------------------------- | |
// withHour() | |
//----------------------------------------------------------------------- | |
@Test |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment