Quick links
Basic Clock
This very small Java project was my first school practise work. Teacher asked us to create a clock using a counter collection.
As my first Java project, I was very pleased to code something very clean and very smart (I think).
This project is hosted on Github.
Download
Basic Clock v.1.01
2010-03-11 — ZIP package (120 Ko)
Changelog
Version 1.01 — 2010-03-11
- ADDED: full Java documentation for classes
- CHANGED: Clock extends from CounterCollector
- CHANGED: Clock.work() and Clock.workOnce() throws InterruptedException
- CHANGED: Clock.getValue(String format) retuns on-demand formatted clock value instead of setting new format using Clock.setFormat()
Version 1.00 — 2010-03-07
- First release
How to?
What you need:
- Java runtime
- Java Compiler (javac)
- Basic programmer skills
Setup
Firstly, you need to compil Java source files with javac:
~% cd basic-clock_v.1.00/
~/basic-clock_v.1.00% javac *.java
Now, run the CounterTest to check if the counter works well:
~/basic-clock_v.1.00% java CounterTest
*** COUNTER INCREMENT CAMPAIGN TEST START ***
[SUCCESS] START STATE
[SUCCESS] DEFAULT INCREMENT 100 STATE
[SUCCESS] RESET STATE
[SUCCESS] START 10 INCREMENT 15 STATE
[SUCCESS] START 0 END 10 INCREMENT 12 STATE
[SUCCESS] START 0 END 100 STEP 10 INCREMENT 12 STATE
[SUCCESS] SETTER
[SUCCESS] GETTER
*** COUNTER INCREMENT CAMPAIGN TEST END ***
*** COUNTER DECREMENT CAMPAIGN TEST START ***
[SUCCESS] START STATE
[SUCCESS] START 0 END 10 DECREMENT 12 STATE
[SUCCESS] RESET STATE
[SUCCESS] START 0 END 100 STEP 10 DECREMENT 12 STATE
[SUCCESS] SETTER
[SUCCESS] GETTER
*** COUNTER DECREMENT CAMPAIGN TEST END ***
~/basic-clock_v.1.00%
Let's start the application:
~/basic-clock_v.1.00% java Main
Current time: 01 23'58
Current time: 01 23'59
Current time: 01 24'00
Current time: 01 24'01
...
Source code
Check out the last version of the source code on the dedicated Github project page.
Counter.java source code
/**
* Counter class
* @author Joris Berthelot <admin@eexit.net>
* @copyright Copyright (c) 2010, Joris Berthelot
* @version 1.00
*/
public class Counter
{
/**
* The counter step
* @since 1.00
* @version 1.00
*/
private int step;
/**
* The counter start value
* @since 1.00
* @version 1.00
*/
private int start;
/**
* The counter end value (could be inferior to the start value)
* @since 1.00
* @version 1.00
*/
private int end;
/**
* The counter value
* @since 1.00
* @version 1.00
*/
private int value;
/**
* The counter state (if the counter reached given limits)
* @since 1.00
* @version 1.00
*/
private boolean ended;
/**
* Counter default constructor
* @since 1.00
* @version 1.00
*/
public Counter()
{
this.step = 1;
this.start = 0;
this.end = Integer.MAX_VALUE;
this.value = 0;
this.ended = false;
}
/**
* Counter constructor with start configuration
* @param int start Start value
* @since 1.00
* @version 1.00
*/
public Counter(int start)
{
this();
this.start = this.value = start;
}
/**
* Counter constructor with start and end configuration
* @param int start Start value
* @param int end End value
* @since 1.00
* @version 1.00
*/
public Counter(int start, int end)
{
this(start);
this.end = end;
}
/**
* Counter constructor with start, end and step configuration
* @param int start Start value
* @param int end End value
* @param int step Step value
* @since 1.00
* @version 1.00
*/
public Counter(int start, int end, int step)
{
this(start, end);
this.step = step;
}
/**
* Counter value setter
* @param int value The counter value to set
* @return Counter The current instance
* @since 1.00
* @version 1.00
*/
public Counter setValue(int value)
{
if (this.start >= this.end) {
if (value <= this.end) {
this.value = this.end;
this.ended = true;
} else if (value >= this.start) {
this.value = this.start;
this.ended = false;
} else {
this.value = value;
}
} else {
if (value >= this.end) {
this.value = this.end;
this.ended = true;
} else if (value <= this.start) {
this.value = this.start;
this.ended = false;
} else {
this.value = value;
}
}
return this;
}
/**
* Counter value getter
* @return int The counter current value
* @since 1.00
* @version 1.00
*/
public int getValue()
{
return this.value;
}
/**
* Counter step getter
* @return int The counter step value
* @since 1.00
* @version 1.00
*/
public int getStep()
{
return this.step;
}
/**
* Counter start getter
* @return int The counter start value
* @since 1.00
* @version 1.00
*/
public int getStart()
{
return this.start;
}
/**
* Counter end getter
* @return int The counter end value
* @since 1.00
* @version 1.00
*/
public int getEnd()
{
return this.end;
}
/**
* Counter is ended state
* @return boolean The counter ended state
* @since 1.00
* @version 1.00
*/
public boolean isEnded()
{
return this.ended;
}
/**
* Counter increment method
* @return Counter The current instance
* @since 1.00
* @version 1.00
*/
public Counter increment()
{
if (!this.isEnded()) {
this.value += this.step;
if (this.value >= this.end) {
this.ended = true;
}
}
return this;
}
/**
* Counter decrement method
* @return Counter The current instance
* @since 1.00
* @version 1.00
*/
public Counter decrement()
{
if (!this.isEnded()) {
this.value -= this.step;
if (this.value <= this.end) {
this.ended = true;
}
}
return this;
}
/**
* Counter reset method
* @return Counter The current instance
* @since 1.00
* @version 1.00
*/
public Counter reset()
{
this.value = this.start;
this.ended = false;
return this;
}
/**
* Counter output method (overloads toString())
* @return String The counter value
* @since 1.00
* @version 1.00
*/
public String toString()
{
return Integer.toString(this.getValue());
}
}
CounterCollector.java source code
/**
* CounterCollector class
* @author Joris Berthelot <admin@eexit.net>
* @copyright Copyright (c) 2010, Joris Berthelot
* @version 1.00
*/
public class CounterCollector
{
/**
* Number of counters object in the collector
* @since 1.00
* @version 1.00
*/
private int nb_counters = 0;
/**
* Array of counter objects
* @since 1.00
* @version 1.00
*/
private Counter counters[];
/**
* CounterCollector default constructor
* @param int nb_counters Number of counter to add
* @since 1.00
* @version 1.00
*/
public CounterCollector(int nb_counters)
{
this.counters = new Counter[nb_counters];
if (0 < nb_counters) {
for (int i = 0; i < nb_counters; i++) {
this.counters[i] = new Counter();
this.nb_counters++;
}
}
}
/**
* CounterCollector constructor with counter values
* @param int nb_counters Number of counter to add
* @param int[] values Values of each counter
* @since 1.00
* @version 1.00
*/
public CounterCollector(int nb_counters, int[] values)
{
this(nb_counters);
if (values.length == nb_counters) {
for (int i = 0; i < nb_counters; i++) {
this.counters[i].setValue(values[i]);
}
}
}
/**
* CounterCollector constructor with start, end and step values
* @param int nb_counters Number of counters to add
* @param int[] start Start values for each counter
* @param int[] end End values for each counter
* @param int[] step Step values for each counter
* @since 1.00
* @version 1.00
*/
public CounterCollector(int nb_counters, int[] start, int[] end, int[] step)
{
this(nb_counters);
if (start.length == nb_counters
&& end.length == nb_counters
&& step.length == nb_counters
) {
for (int i = 0; i < nb_counters; i++) {
this.counters[i] = new Counter(start[i], end[i], step[i]);
}
}
}
/**
* Counter getter
* @param int index The index of counter to get
* @return Counter|null The wanted counter object or null of object doesn't
* exist
* @since 1.00
* @version 1.00
*/
public Counter getCounter(int index)
{
if (this.counters[index] instanceof Counter) {
return this.counters[index];
}
return null;
}
/**
* CounterCollector increment method
* @return CounterCollector The current instance
* @since 1.00
* @version 1.00
*/
public CounterCollector increment()
{
int i = 0;
if (0 < this.nb_counters) {
while (i < this.nb_counters) {
this.counters[i].increment();
if (this.counters[i].isEnded()) {
this.counters[i].reset();
i++;
} else {
break;
}
}
}
return this;
}
/**
* CounterCollector decrement method
* @return CounterCollector The current instance
* @since 1.00
* @version 1.00
*/
public CounterCollector decrement()
{
int i = 0;
if (0 < this.nb_counters) {
while (i < this.nb_counters) {
this.counters[i].decrement();
if (this.counters[i].isEnded()) {
this.counters[i].reset();
i++;
} else {
break;
}
}
}
return this;
}
}
Clock.java source code
import java.util.*;
/**
* Clock class
* @author Joris Berthelot <admin@eexit.net>
* @copyright Copyright (c) 2010, Joris Berthelot
* @version 1.01
*/
public class Clock extends CounterCollector
{
/**
* Clock start values (sec, min, hrs)
* @since 1.00
* @version 1.01
*/
private static int start[] = {0, 0, 0};
/**
* Clock end values (sec, min, hrs)
* @since 1.00
* @version 1.00
*/
private static int end[] = {60, 60, 24};
/**
* Clock step values (sec, min, hrs)
* @since 1.00
* @version 1.01
*/
private static int step[] = {1, 1, 1};
/**
* Clock default output format
* @since 1.00
* @version 1.00
*/
private String format = "%h%:%m%:%s%";
/**
* Clock constructor
* @since 1.00
* @version 1.01
*/
public Clock()
{
super(3, start, end, step);
}
/**
* Clock work method (this makes the clock working)
* @return Clock The current instance
* @throws InterruptedException Thread.sleep() error
* @since 1.00
* @version 1.01
*/
public Clock work()
{
try {
while (true) {
System.out.println(this);
Thread.sleep(1000);
this.increment();
}
} catch (InterruptedException e) {
System.out.println("ERROR: " + e);
}
return this;
}
/**
* Clock work once method (same as Clock.work() but loops one time). Useful
* when manual incrementation needed (tests, suitable cases).
* @return Clock The current instance
* @throws InterruptedException Thread.sleep() error
* @since 1.00
* @version 1.01
*/
public Clock workOnce()
{
try {
System.out.println(this);
Thread.sleep(1000);
this.increment();
} catch (InterruptedException e) {
System.out.println("ERROR: " + e);
}
return this;
}
/**
* Clock output format setter
* @param String format The new output format (need to include %h%, %m% and %s%)
* @return Clock The current instance
* @since 1.00
* @version 1.00
*/
public Clock setFormat(String format)
{
this.format = format;
return this;
}
/**
* Clock hour value setter
* @param int hrs The new hour value to set
* @return Clock The current instance
* @since 1.00
* @version 1.00
*/
public Clock setHrs(int hrs)
{
this.getCounter(2)
.setValue(hrs);
return this;
}
/**
* Clock minute value setter
* @param int min The new minute value to set
* @return Clock The current instance
*/
public Clock setMin(int min)
{
this.getCounter(1)
.setValue(min);
return this;
}
/**
* Clock second value setter
* @param int sec The new second value to set
* @return Clock The current instance
* @since 1.00
* @version 1.00
*/
public Clock setSec(int sec)
{
this.getCounter(0)
.setValue(sec);
return this;
}
/**
* Clock global value (hours, minute, second) setter
* @param int hrs The new hour value to set
* @param int min The new minute value to set
* @param int sec The new second value to set
* @since 1.00
* @version 1.00
*/
public Clock setValue(int hrs, int min, int sec)
{
this.setHrs(hrs)
.setMin(min)
.setSec(sec);
return this;
}
/**
* Clock hour value getter
* @return String The current hour formatted ("%02d") value
* @since 1.00
* @version 1.00
*/
public String getHrs()
{
return String.format("%02d",
this.getCounter(2)
.getValue()
);
}
/**
* Clock minute value getter
* @return String The current minute formatted ("%02d") value
* @since 1.00
* @version 1.00
*/
public String getMin()
{
return String.format("%02d",
this.getCounter(1)
.getValue()
);
}
/**
* Clock second value getter
* @return String The current second formatted ("%02d") value
* @since 1.00
* @version 1.00
*/
public String getSec()
{
return String.format("%02d",
this.getCounter(0)
.getValue()
);
}
/**
* Clock global value (hour, minute, second) getter
* @return String The current clock formatted ({@link Clock.format}) value
* @since 1.00
* @version 1.00
*/
public String getValue()
{
return this.format
.replaceAll("%h%", this.getHrs())
.replaceAll("%m%", this.getMin())
.replaceAll("%s%", this.getSec());
}
/**
* Clock global value (hour, minute, second) getter with format arg
* @param String format The on-demand wanted format value (see {@link Clock.setFormat}).
* @return String The current clock formatted value
* @since 1.00
* @version 1.01
*/
public String getValue(String format)
{
return format
.replaceAll("%h%", this.getHrs())
.replaceAll("%m%", this.getMin())
.replaceAll("%s%", this.getSec());
}
/**
* Clock default output method (outputs with {@link Clock.format})
* @return String The current clock formatted ({@link Clock.format}) value
* @since 1.00
* @version 1.00
*/
public String toString()
{
return this.getValue();
}
}
Main.java source code
import java.util.*;
public class Main
{
private static Clock clock;
public static void main(String[] args)
{
Calendar time = Calendar.getInstance(
TimeZone.getTimeZone("Europe/Paris")
);
Clock clock = new Clock();
clock.setValue(
time.get(time.HOUR_OF_DAY),
time.get(time.MINUTE),
time.get(time.SECOND)
)
.setFormat("Current time: %h% %m%'%s%")
.work();
}
}
Open Source Licence
Basic Clock uses the MIT Licence.
Copyright © 2010-2018, Joris Berthelot.
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.