This is a read-only snapshot of the ComputerCraft forums, taken in April 2020.
surferpup's profile picture

Real World / MinecraftWorld Time Display Program *New Ver 2.0

Started by surferpup, 11 January 2014 - 01:39 AM
surferpup #1
Posted 11 January 2014 - 02:39 AM
TimeDisplays v. 2.0

This fairly simple program will display Real World time for up to three timezones (pulling time from time.org) and Minecraft world (local) time on the computer as well as on any number of wired attached monitors. I wrote it for a gathering area of sorts on my servers (the area serves as a transit station). The players on my server seem to think it is fun to have going. We have a chunk loader in this area, so the program is constantly active. This version is cleaner and pretty well de-bugged. Let me know what you think. The program uses http access as well as the parallel API to update the displays of time.

Screen Shot




Multi-Monitor





Change Log
  • Added screenshots to this page
  • Added Parallel functionality in coroutines (thanks [member='Lyqyd'] for the info)
  • Remove a debug feature (no longer necessary)
  • Resolved issue where not booting (or very slow booting) on computer startup
  • Cut down on number of calls to refreshTime()
  • Added some commenting and reorganized code
  • Created a new API to obtain real world date and time. The Real World Time API is now in beta.

Features
  • Will print to computer (normal or advanced) as well as any specified monitors
  • Can specify city names and timezones in the time{} array.
  • Can specify and add new monitors in the monitors{} array.
  • Adjusts for color or non-color monitors
  • Attempts to maximize display size based on length of the longest city name while having at least 8 display lines.
  • Utilizes http access and pulls time from http://www.timeapi.org
  • Utilizes Parallel API for individual timer intervals on real world and Minecraft world time.

Usage
  • Place computer, type in
    pastebin get AUQfZjRK startup
  • Restart computer
  • Attach a wired modem to the computer, and use network cable and additional wired modems to attach additional monitors of any size (with or without color capability)
  • For each monitor, modify the code, specifying the monitor label where indicated in the examples (i.e., monitor_1)
  • To change time zones, use any timezone designation consistent with the API of http://www.timeapi.org.

Code

-----------------------------------------------------------------------
--[[   TimeDisplays v 2.0
by Surferpup

	This program displays real world for 3 time zone
	and minecraft time on a computer and (optionally)
	on as many wired monitors as are declared.

	The program as configured does not have any monitors declared.
	Simply go to the monitor section and uncomment/add monitor lines
	as necessary.

	The program will take advantage of color computers and monitors.

	Save this program as startup if you want it to run on block load.

]]
-----------------------------------------------------------------------
local mcInterval = 1 -- the polling interval for Minecraft Time updates
local rwInterval= 60 -- the polling world for real world time updates
-----------------------------------------------------------------------
--  MONITORS
--  You can have as many as you'd like
--  you need to change this to your monitor labels
--  format [n] = peripheral.wrap("monitor_label)
--  Don't forget commas between all BUT the last entry
--
--  I formated three for you and commented them out.
------------------------------------------------------------------------
local monitors = {
--	[1]=peripheral.wrap("monitor_0");
--	[2]=peripheral.wrap("monitor_1");
--	[3]=peripheral.wrap("monitor_2");
}
-----------------------------------------------------------------------
--  TIME ZONES
--  3 real world and 1 local (minecraft) time zone
--  change zone to be a zone recognized by www.timeapi.org
--  go to timeapi.org and get your own strings using the same exact format
------------------------------------------------------------------------
local time = {
	[1]={city="Sioux Falls",color=colors.lightBlue,time="NOW",zone = "cst"}, -- central
	[2]={city="Osaka",color=colors.yellow,time="NOW",zone = "utc"}, -- universal
	[3]={city="Livermore",color=colors.lime,time="NOW",zone = "pst"}, -- pacific
	[4]={city="Local",color=colors.pink,time="NOW",zone = ""} -- This is minecraft time
}
function refreshTime()
	for i = 1,3 do
		time[i].time=(http.get("http://www.timeapi.org/"..(time[i].zone).."/now?format=%25l:%25M%20%25p").readAll())
	end
	time[4].time= textutils.formatTime(os.time(), false)
end
------------------------------------------------------------------------
-- OTHER LOCAL VARIABLES
local minecraftTimer,realWorldTimer,rwTime,mcWorldTime,maxLabelSize
------------------------------------------------------------------------
-- FUNCTIONS

function pad(width,text)
	return (string.rep(" ",width-string.len(text))..text)
end

local function clearAllScreens()
	term.clear()
	for i = 1,#monitors do
			monitors[i].clear()
	end
end

function calculateMaxLabelSize() -- city names vary in size
	local maxLabelSize = 0
	for i= 1,4 do
if #(time[i].city)>maxLabelSize then
   maxLabelSize = #(time[i].city)
end
	end
	return maxLabelSize
end

local function setScale(maxLabelSize) -- fit city names to varying size monitors
	for i = 1,#monitors do
for j=10,1,-1 do
   monitors[i].setTextScale(j/2)
   local mX,mY = monitors[i].getSize()
   if mY>=8 then
if mX>maxLabelSize then
   break
end
   end
end
	end
end

function displayRealWorldTime()
	while true do
		local e = {os.pullEvent()} -- this will yield back to main loop
		if (e[1] == "timer" and e[2] == realWorldTimer) or e[1]=="start" then
   refreshTime()
			for t = 1,4 do

					if term.isColor() then
						term.setTextColor(tonumber(time[t].color))
					else
						term.setTextColor(colors.white)
					end
					term.setCursorPos(1,t)
   term.clearLine()
					x,_ = term.getSize()
					term.write(pad(x,time[t].time))
					term.setCursorPos(1,t)
					term.write(time[t].city)
			end
			term.setTextColor(colors.white) -- reset terminal to default color
			for i = 1,#monitors do
				for t = 1,4 do
   local x,_ = monitors[i].getSize()
					monitors[i].setCursorPos(1,2*t-1)
   monitors[i].clearLine()
					if monitors[i].isColor() then
						monitors[i].setTextColor(tonumber(time[t].color))
					else
						monitors[i].setTextColor(colors.white)
					end
					monitors[i].write(time[t].city)
					monitors[i].setCursorPos(1,t*2)
					monitors[i].write(pad(x,time[t].time))
				end
			end
			realWorldTimer = os.startTimer(rwInterval)
		end

	end
end

function displayMinecraftWorldTime()
	while true do
local e = {os.pullEvent()} -- this will yield back to main loop
		if (e[1] == "timer" and e[2] == minecraftTimer) or e[1]=="start" then
			time[4].time= textutils.formatTime(os.time(), false)
			for i = 1,#monitors do
				monitors[i].setCursorPos(1,8)
monitors[i].clearLine()
				if monitors[i].isColor() then
					monitors[i].setTextColor(tonumber(time[4].color))
				end
				local x,_ = monitors[i].getSize()
				monitors[i].write(pad(x,time[4].time))
			end
			term.setCursorPos(1,4)
   term.clearLine()
			if term.isColor() then
				term.setTextColor(tonumber(time[4].color))
			end
			x,_ = term.getSize()
			term.write(pad(x,time[4].time))
			term.setCursorPos(1,4)
			term.write(time[4].city)
			if term.isColor()
				then term.setTextColor(colors.white)
			end
			minecraftTimer=os.startTimer(mcInterval)
		end
	end
end

local function realWorldTime() -- coroutine driver in parallel
	local tFilter = nil
	local eventData = {}
	local r = rwTime -- coroutine
	while true do
		if r then
			if tFilter == nil or tFilter == eventData[1] or eventData[1] == "terminate" then
				local ok, param = coroutine.resume( r, unpack(eventData) )
				if not ok then
					error( param )
				else
					tFilter = param
				end
				if coroutine.status( r ) == "dead" or eventData[1] == "terminate" then
					r = nil
					event = "terminate"
					return
				end
			end
		end
		eventData = { os.pullEventRaw() }
	end
end

local function mineCraftTime() -- coroutine driver in parallel
	local tFilter = nil
	local eventData = {}
	local r = mcWorldTime --coroutine
	while true do
		if r then
			if tFilter == nil or tFilter == eventData[1] or eventData[1] == "terminate" then
				local ok, param = coroutine.resume( r, unpack(eventData) )
				if not ok then
					error( param )
				else
					tFilter = param
				end
				if coroutine.status( r ) == "dead" or eventData[1] == "terminate" then
					r = nil
					event = "terminate"
					return
				end
			end
		end
		eventData = { os.pullEventRaw() }
	end
end  

local function start()
	sleep(.5)
	os.queueEvent("start")
	return
end
-----------------------------------------------------------------------
--  MAIN PROGRAM
-----------------------------------------------------------------------
minecraftTimer = 0
realWorldTimer = 0

-- create coroutines
rwTime = coroutine.create(displayRealWorldTime)
mcWorldTime = coroutine.create(displayMinecraftWorldTime)

-- calculate maxLabelSize
maxLabelSize = calculateMaxLabelSize()

-- set Scale for Monitors
setScale(maxLabelSize)
clearAllScreens()


-- Start Parallel functions
--
--[[
	The program uses coroutines in conjuction with
	parallel functions.  The first function (start) will
	queue a start event.  The next two functions drive
	coroutines which update minecraft time or real world time.

	Thanks to Lyqyd on ComputerCraft forums for the
	ideas behind the coroutine driving functions running
	in parallel
]]

parallel.waitForAll(start,mineCraftTime,realWorldTime)

Paste bin link: http://pastebin.com/AUQfZjRK

Thanks to Lyqyd, theoriginalbit, Death and Bubba for the help.
Edited on 02 February 2014 - 01:59 AM
Lyqyd #2
Posted 11 January 2014 - 01:27 PM
Moved to Programs.
oeed #3
Posted 13 January 2014 - 03:24 AM
This looks pretty cool, an API would be even cooler though, why not look in to making a real world time API?
surferpup #4
Posted 14 January 2014 - 10:54 PM
When I tackle coding up an API, it will be first on my list. I just figured out how to do programs in Lua. How bout giving me a point in the right direction?
oeed #5
Posted 14 January 2014 - 11:21 PM
When I tackle coding up an API, it will be first on my list. I just figured out how to do programs in Lua. How bout giving me a point in the right direction?

Sure, I'm not sure if there's any tutorial, you might want to have a look. I'll give a brief example though.

Make a file for you API, in this case I'll call it 'example'.

Each function/variable in the API file can be access. For example,

--this can only be accessed within this file
local helloText = 'Hello'
function hello()
    print(helloText)
end
bye = 'Good bye'

Then, in a program you could run:

os.loadAPI('example')
example.hello()
--prints 'Hello'
print(example.bye)
--prints 'Good bye'
print(example.helloText)
--doesn't work

Feel free to PM me if you need any more help.
surferpup #6
Posted 15 January 2014 - 12:54 AM
Got it. An API is thus like a library. Thanks.
oeed #7
Posted 15 January 2014 - 01:17 AM
Got it. An API is thus like a library. Thanks.

Yep. Your welcome.
Symmetryc #8
Posted 20 January 2014 - 10:34 AM
It should also be noted that you can use APIs through the use of the dofile function as an import-like statement, that way you can keep all of the variables local, thus not polluting the global environment and achieving the additional speed boost that comes with local variables.

Example API:

return {
  get_time = function()
    --#do stuff
  end;
}
Example Program using this API:

local time = dofile("time.lua")
print(time.get_time())
surferpup #9
Posted 02 February 2014 - 02:56 AM
I have now made the ability to grab real world date and time an API. The Real World Time API is now in beta and open for review.
xBoom #10
Posted 08 March 2014 - 07:04 PM
Is there any way to extend the code so you can have more then 3 times zones, if so how

Thanks for any help - xBoom
viveleroi #11
Posted 19 April 2014 - 03:27 AM
I'm trying this now, great work!

I'm noticing that BST time is wrong in the API. Currently London uses BST, which is UTC+1 in the summer, but shows as UTC+2 on the api.